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)
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
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.
@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
@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
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 :)
So what's wrong with my example? Why does it work as it is ?
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.
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.
I get SEGFAULT
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
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
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.
Perhaps. After making use of argc, argv etc. if we need it
Did you already try main args ?
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.
I'm not against ABI . I simply wanted to show you that rsp at main entry contains meaningful info.
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.
Try this:
...
.code
main:
and rsp, -16
invoke printf,CStr("argc = %d ",10), [rdi] ; [rsp]
...
EDIT: forgot square brackets, corrected
It makes sense because rdi will be used for the first argument. Assemblers are low-level tools, we need to know how things happen.
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?
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.
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
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
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?
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.