The MASM Forum

64 bit assembler => UASM Assembler Development => Topic started by: aw27 on December 20, 2017, 08:28:17 PM

Title: Stack alignment problem in Linux
Post by: aw27 on December 20, 2017, 08:28:17 PM
I decided to play with the gtk sample and convert it to 64-bit Linux. It took me a few hours to find the reason it crashed - debugging facilities for ASM in Linux are miserable.

Suddenly, I had an ephiphany (after looking at the value of rsp  :bgrin:) - the alignment!


; 1. assemble:       ./uasm -elf64 -Fo=gtk.o gtk.asm
; 2. link with gcc:   gcc -s -o gtk -I/lib64/ld-linux-x86-64.so.2 gtk.o `pkg-config --libs gtk+-3.0`


LPVOID TYPEDEF PTR VOID

public main

gtk_init proto :PTR, :PTR
gtk_init_check proto :PTR, :PTR
gtk_window_new proto :DWORD
gtk_window_set_title proto :PTR, :PTR
gtk_table_new proto :DWORD, :DWORD, :DWORD ; rows, columns, homogeneous
gtk_grid_new proto

gtk_table_attach_defaults proto :PTR, :PTR, :DWORD, :DWORD, :DWORD, :DWORD
gtk_grid_attach proto :PTR, :PTR, :DWORD, :DWORD, :DWORD, :DWORD

gtk_container_add proto :PTR, :PTR
gtk_grid_attach proto :PTR, :PTR, :DWORD, :DWORD, :DWORD, :DWORD
gtk_box_pack_start proto :PTR, :PTR, :DWORD, :DWORD, :DWORD


gtk_button_new_from_stock  proto :PTR
gtk_button_new_with_label proto :PTR

gtk_label_new proto :PTR
gtk_widget_show_all proto :PTR
gtk_widget_show proto :PTR
gtk_main proto
gtk_main_quit proto
g_signal_connect_data proto :PTR, :QWORD, :QWORD, :QWORD, :QWORD, :DWORD

puts  proto :PTR
exit  proto :DWORD

.data
no_int db 'No gtk_init',0
wincap db 'Hello World', 0
labelcap db 'jwasm gtk example', 0
quitbut db 'gtk-quit',0
no_win_err db 'No Window',0
sdel_event db 'delete-event',0
sclicked db 'clicked',0
align 16
nullPtr LPVOID 0

.data?
align 16   
window dq ?
table dq ?
gtklabel dq ?
button dq ?

.code

main:    ; let the ritual begin.
and rsp, -16 ; --------------  REQUIRED!
;make sure we have gtk
invoke gtk_init_check,nullPtr,nullPtr
.if (eax == 0)
    invoke puts, offset no_int
    jmp Terminate
.endif
;create window
invoke gtk_window_new, 0
.if (rax == 0)
    invoke puts, offset no_win_err
    jmp Terminate
.endif
mov window, rax

invoke gtk_window_set_title,window, offset wincap
invoke gtk_table_new,15, 15, 1
mov table,rax
invoke gtk_container_add,window,table

invoke gtk_label_new,addr labelcap
mov [gtklabel],rax

;mov rdi, table
;mov rsi, gtklabel
;mov edx, 1
;mov ecx, 8
;mov r8d, 3
;mov r9d, 7
;call gtk_table_attach_defaults
invoke gtk_table_attach_defaults,table,gtklabel,1, 8, 3, 7

invoke gtk_button_new_from_stock,offset quitbut
mov button,rax
;mov rdi, table
;mov rsi, button
;mov edx, 10
;mov ecx, 14
;mov r8d, 12
;mov r9d, 14
;call gtk_table_attach_defaults
invoke gtk_table_attach_defaults,table,button, 10, 14, 12, 14


;Show whole GUI
invoke gtk_widget_show_all,window
;invoke gtk_widget_show,window
;invoke gtk_widget_show,table
;invoke gtk_widget_show,gtklabel

;attache signals
invoke g_signal_connect_data,window,offset sdel_event,offset exit_prog,0, 0, 0
invoke g_signal_connect_data,button,offset sclicked,offset exit_prog,0, 0, 0
;Do it
invoke gtk_main
;------------------------------------------------------------------------------
;Callback for closing window
exit_prog proc
    invoke gtk_main_quit

exit_prog endp

Terminate:
    invoke exit, 0

end main


(http://www.atelierweb.com/a/ubuntu.jpg)

Title: Re: Stack alignment problem in Linux
Post by: Biterider on December 20, 2017, 09:05:53 PM
Hi
It seems similar to that what happens on Windows.
I solved it calling a proc as main entry point. Making it this way, UASM is able to adjust the stack and reserve the homing space for the callees.
Just my 2 cents.


Biterider

Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 20, 2017, 09:18:48 PM
Quote from: Biterider on December 20, 2017, 09:05:53 PM
Hi
It seems similar to that what happens on Windows.
This was an old problem, it was solved at a certain point, I don't know how things currently are.
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 20, 2017, 09:27:38 PM
@aw27:
              Which Linux distro / version do you use?

I don't have any alignment problems on Ubuntu 14.04
This minimalistic example works fine here

; Simple GTK3 window example
;
; ASSEMBLE:  ./uasm  -elf64  window.asm
;     LINK:    gcc ./window.o -o ./window `pkg-config --libs gtk+-3.0 gthread-2.0 gobject-2.0 gmodule-no-export-2.0`
;
;     NOTE:   The program has to be started and terminated from console ( by pressing Ctrl-C )

GTK_WINDOW_TOPLEVEL = 0

gtk_init        proto  :QWORD, :QWORD
gtk_window_new  proto  :QWORD
gtk_widget_show proto  :QWORD
gtk_main        proto

.code
      main:
   
      invoke gtk_init,0,0       
      invoke gtk_window_new,GTK_WINDOW_TOPLEVEL
      invoke gtk_widget_show, rax
        call gtk_main
               
end  main

NB:
- You may need adjust link command line to your GTK  version ( default is 3)
- Start it from command line and terminate it by pressing Ctrl-C
- This sample is meant to be zero level GTK window example
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 20, 2017, 09:38:46 PM
@GoneFishing
I was using 16.04. Your example shall work fine as well (I have not tested), because the segfault happens only in some instructions. In the example it happens on the gtk_widget_show_all after gtk_table_attach_defaults. That's why I tried to see if it was problem of the invoke gtk_table_attach_defaults itself
Title: Re: Stack alignment problem in Linux
Post by: johnsa on December 21, 2017, 12:30:13 AM
If the entry point is just a label it will always be out from the call to the entry point, the and rsp,X option would work.. or make the entry point a proc to do it automatically :)
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 01:18:07 AM
So what's wrong with my example? Why does it work as it is ?
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 02:01:48 AM
Quote from: johnsa on December 21, 2017, 12:30:13 AM
If the entry point is just a label it will always be out from the call to the entry point, the and rsp,X option would work.. or make the entry point a proc to do it automatically :)
I understand, you have no reliable way to know where the entry point is, so you can not realign the stack, all must be done manually.
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 02:05:40 AM
Quote from: GoneFishing on December 21, 2017, 01:18:07 AM
So what's wrong with my example? Why does it work as it is ?
insert this movaps instruction, like this:

invoke gtk_init,0,0
movaps xmm0, [rsp] ;and see if it works.
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 02:17:41 AM
I get SEGFAULT
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 02:22:15 AM
Quote from: GoneFishing on December 21, 2017, 02:17:41 AM
I get SEGFAULT
Now you know the stack is not aligned.  :(
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 02:37:23 AM
Later I'll post small test app that walks the stack on main entry.
If we link our app to  libc __libc_start_main will prepare the stack on main entry. It looks like this:
Quote=================================================================
        %rsp        The stack contains the arguments and environment:
      0(%rsp)                  argc
      LP_SIZE(%rsp)           argv[0]
      ...
      (LP_SIZE*argc)(%rsp)     NULL
      (LP_SIZE*(argc+1))(%rsp)  envp[0]
      ...
                            NULL
      ================================================================            

Small example:

; link: ld -s ./1.o -o 1 -I/lib64/ld-linux-x86-64.so.2 -lc

exit proto systemv status:dword
printf PROTO SYSTEMV pformat:PTR, arg:VARARG
         
.code     
     main:
     
       invoke printf,CStr("argc = %d ",10),  [rsp]
     
        invoke exit,0
     
end  main
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 02:41:18 AM

OPTION LITERALS:ON

extern __libc_start_main:proc

exit proto systemv status:dword
printf PROTO SYSTEMV pformat:PTR, arg:VARARG

IF 0
       =================================================================
       /home/doc/PROJECTS/eglibc-2.19/sysdeps/x86_64/start.S
       =================================================================
        %rsp   The stack contains the arguments and environment:
0(%rsp)       argc
LP_SIZE(%rsp)   argv[0]
...
(LP_SIZE*argc)(%rsp)   NULL
(LP_SIZE*(argc+1))(%rsp)  envp[0]
...
          NULL
================================================================
ENDIF

GetMainArgs macro arg
            add r15,8
            xor r14,r14
           .while  qword ptr [r15][rsp] != 0
               invoke printf,CStr("%s[%d] = %s ",10), arg, r14, [r15][rsp]
               add r15,8
               inc r14
          .endw     
      endm     

         
.code     
     main:
     
       invoke printf,CStr("argc = %d ",10),  [rsp]
     
       xor r15, r15
     
       GetMainArgs "argv"
       GetMainArgs "envp"
           
       invoke exit,0
     
end  main ;  __libc_start_main ;  _start


LINK command line: ld -s ./1.o -o 1 -I/lib64/ld-linux-x86-64.so.2 -lc
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 02:52:08 AM
When start_main calls your code the stack is aligned but since the return address is pushed on the stack it becomes not aligned, it is the job of the called function to realign it. UASM relies on you to realign the stack because they can not detect where start_main  called to.
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 03:01:09 AM
Perhaps. After making use of argc, argv etc. if we need it
Did you already try main args ?

Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 03:08:35 AM
Quote from: GoneFishing on December 21, 2017, 03:01:09 AM
Perhaps. After making use of argc, argv etc. if we need it
Did you already try main args ?
I have not tried anything, these are the ABI rules. The caller is expected to call with stack aligned no matter how many arguments are pushed on the stack. This applies both to Windowz  :biggrin: and SystemV.
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 03:29:25 AM
I'm not against ABI . I simply wanted to show you that rsp at main entry contains meaningful info.
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 03:34:39 AM
Quote from: GoneFishing on December 21, 2017, 03:29:25 AM
I'm not against ABI . I simply wanted to show you that rsp at main entry contains meaningful info.
May not contain anything interesting because pointers to argc and argv come in rdi and rsi.
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 03:39:46 AM
Try this:

...
.code     
     main: 
       and rsp, -16   
       invoke printf,CStr("argc = %d ",10), [rdi] ; [rsp]
...

EDIT: forgot square brackets, corrected
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 03:58:21 AM
It makes sense because rdi will be used for the first argument. Assemblers are low-level tools, we need to know how things happen.
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 04:24:02 AM
I agree.
It makes sense how to work with labels as entry point .  Now what if you want to pass real argc and argv to gtk_init not just nulls.
How would you do it?
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 04:52:55 AM
Quote from: GoneFishing on December 21, 2017, 04:24:02 AM
I agree.
It makes sense how to work with labels as entry point .  Now what if you want to pass real argc and argv to gtk_init not just nulls.
How would you do it?
I don't know much about GTK, but I don't really see where your problem stands as far as ASM is concerned.
For documentation about GTK better you have a look at the Gnome website. GTK has a huge amount of functions. I also became aware that some of the functions I used in my example are deprecated and I have even prototyped the ones that replace them but ended not using them because it was out of scope.
Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 05:10:11 AM
gtk_init takes 2 parameters: argc and argv
In the gtk1 example nullPtr's were used . That's why I asked you . I know about online GNOME docs I perfectly can use it.
Well , let's stop for today. Thanks for your time and efforts
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 06:17:20 AM
Quote from: GoneFishing on December 21, 2017, 05:10:11 AM
gtk_init takes 2 parameters: argc and argv
In the gtk1 example nullPtr's were used . That's why I asked you . I know about online GNOME docs I perfectly can use it.
Well , let's stop for today. Thanks for your time and efforts
I understand your point, you don't believe that the arguments passed from the command line will reach your ASM program. They will.



public main

puts  proto :PTR
exit  proto :DWORD
printf proto :PTR, :VARARG
strlen proto :PTR

.data
argcount db "count %d",10,0
passedargs db "%s",10,0


.code

main:   
push r12
push r13
push r14
        and rsp, -16
mov r13d, edi
        mov r14, [rsi]

invoke printf, offset argcount, r13d
xor r12, r12
.while r12<r13
invoke printf, offset passedargs, r14
invoke strlen, r14
add r14,rax
inc r14
inc r12
.endw

pop r14
pop r13
pop r12
        invoke exit, 0

end main



Title: Re: Stack alignment problem in Linux
Post by: GoneFishing on December 21, 2017, 06:51:22 AM
I was not sure how to do it technically correct in different variations.
Today we've worked out  first variant  main entry as label
Other possible variants are:
- entry main as proc without args - easy one
- entry main as proc with args       - needs to be discussed

BTW do we  really need  to push all those registers on main entry?
Title: Re: Stack alignment problem in Linux
Post by: aw27 on December 21, 2017, 07:36:07 PM
Quote from: GoneFishing on December 21, 2017, 06:51:22 AM
BTW do we  really need  to push all those registers on main entry?
I don't think so, but have not seen it documented either for Windows or for Linux.