News:

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

Main Menu

Stack alignment problem in Linux

Started by aw27, December 20, 2017, 08:28:17 PM

Previous topic - Next topic

aw27

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





Biterider

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


aw27

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.

GoneFishing

@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

aw27

@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

johnsa

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 :)

GoneFishing

So what's wrong with my example? Why does it work as it is ?

aw27

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.

aw27

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.

GoneFishing


aw27


GoneFishing

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

GoneFishing


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

aw27

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.

GoneFishing

Perhaps. After making use of argc, argv etc. if we need it
Did you already try main args ?