Why do I get a zombie when I link assembly code without stdlib? - std

I was experimenting with assembly code and the GTK+ 3 libraries when I discovered that my application turns into a zombie if I don't link the object file with gcc against the standard library. Here is my code for the stdlib-free application
%include "gtk.inc"
%include "glib.inc"
global _start
SECTION .data
destroy db "destroy", 0 ; const gchar*
strWindow db "Window", 0 ; const gchar*
SECTION .bss
window resq 1 ; GtkWindow *
SECTION .text
_start:
; gtk_init (&argc, &argv);
xor rdi, rdi
xor rsi, rsi
call gtk_init
; window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
xor rdi, rdi
call gtk_window_new
mov [window], rax
; gtk_window_set_title (GTK_WINDOW (window), "Window");
mov rdi, rax
mov rsi, strWindow
call gtk_window_set_title
; g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
mov rdi, [window]
mov rsi, destroy
mov rdx, gtk_main_quit
xor rcx, rcx
xor r8, r8
xor r9, r9
call g_signal_connect_data
; gtk_widget_show (window);
mov rdi, [window]
call gtk_widget_show
; gtk_main ();
call gtk_main
mov rax, 60 ; SYS_EXIT
xor rdi, rdi
syscall
And here is the same code meant to be linked against the standard library
%include "gtk.inc"
%include "glib.inc"
global main
SECTION .data
destroy db "destroy", 0 ; const gchar*
strWindow db "Window", 0 ; const gchar*
SECTION .bss
window resq 1 ; GtkWindow *
SECTION .text
main:
push rbp
mov rbp, rsp
; gtk_init (&argc, &argv);
xor rdi, rdi
xor rsi, rsi
call gtk_init
; window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
xor rdi, rdi
call gtk_window_new
mov [window], rax
; gtk_window_set_title (GTK_WINDOW (window), "Window");
mov rdi, rax
mov rsi, strWindow
call gtk_window_set_title
; g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
mov rdi, [window]
mov rsi, destroy
mov rdx, gtk_main_quit
xor rcx, rcx
xor r8, r8
xor r9, r9
call g_signal_connect_data
; gtk_widget_show (window);
mov rdi, [window]
call gtk_widget_show
; gtk_main ();
call gtk_main
pop rbp
ret
Both applications create a GtkWindow. However, the two behave differently when the window is closed. The former leads to a zombie process and I need to press Ctrl+C. The latter exhibits the expected behaviour, i.e. the application terminates as soon as the window is closed.
My feeling is that the standard lib is performing some essential operations that I am neglecting in the first code sample, but I can't tell what it is.
So my question is: what's missing in the first code sample?

Thanks #MichaelPetch for this idea which explains all the observed symptoms perfectly:
If gtk_main leaves any threads running when it returns, the most important difference between your two programs is that eax=60/syscall only exits the current thread. See the documentation in the _exit(2) man page, which points out that glibc's _exit() wrapper function has used exit_group since glibc2.3.
exit_group(2) is eax=231 / syscall in the x86-64 ABI. This is what the CRT startup/cleanup code runs when main() returns.
You can see this by using strace ./a.out on both versions.
This surprised me at least: A process where the initial thread has exited, but other threads are still running, is shown as a zombie. I tried it on my own desktop (see the end of this answer for build commands and extern declarations so you don't need gtk.inc), and you really do get a process that's reported as a zombie, but that you can ctrl-c to kill the other threads that gtk leaves running when gtk_main returns.
./thread-exit & # or in the foreground, and do the following commands in another shell
[1] 20592
$ ps m -LF -p $(pidof thread-exit)
UID PID PPID LWP C NLWP SZ RSS PSR STIME TTY STAT TIME CMD
peter 20592 7749 - 0 3 109031 21920 - 06:28 pts/12 - 0:00 ./thread-exit
peter - - 20592 0 - - - 0 06:28 - Sl 0:00 -
peter - - 20593 0 - - - 0 06:28 - Sl 0:00 -
peter - - 20594 0 - - - 0 06:28 - Sl 0:00 -
Then close the window: the process doesn't exit, and still has two threads running + 1 zombie.
$ ps m -LF -p $(pidof thread-exit)
UID PID PPID LWP C NLWP SZ RSS PSR STIME TTY STAT TIME CMD
peter 20592 7749 - 0 3 0 0 - 06:28 pts/12 - 0:00 [thread-exit] <defunct>
peter - - 20592 0 - - - 0 06:28 - Zl 0:00 -
peter - - 20593 0 - - - 0 06:28 - Sl 0:00 -
peter - - 20594 0 - - - 0 06:28 - Sl 0:00 -
I'm not sure if ps m -LF is the best command for this, but it seems to work. It indicates that only the main thread has exited after you close the window, and 2 other threads are still running. You can even look at /proc/$(pidof thread-exit)/task directly, instead of using ps to do that for you.
re: comments about not wanting to link libc:
Avoiding the glibc's CRT startup / cleanup (by defining _start instead of _main) isn't the same thing as avoiding libc. Your code doesn't call any libc functions directly, but libgtk does. ldd /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 shows that libgtk depends on libc, so the dynamic linker will map libc into your process anyway. In fact, ldd on your own program says that, even if you don't put -lc on the linker command line directly.
So you could just link libc and call exit(3) from your _start.
See this Q&A for info on building static vs. dynamic binaries that link libc or not and define _start or main, with NASM or gas.
Side-note: the version that defines main doesn't need to make a stack frame with rbp.
If you leave out the push rbp / mov rbp, rsp, you still have to do something to align the stack before the call, but it can be push rax, or still push rbp if you want to be confusing. So:
main:
push rax ; align the stack
...
call gtk_widget_show
pop rax ; restore stack to function-entry state
jmp gtk_main ; optimized tail-call
If you want to keep the frame-pointer stuff, you could still do the tail call, but pop rbp / jmp gtk_main.
PS: for those who want to try it themselves, this change lets you build it without having to go looking for for a gtk.inc:
;%include "gtk.inc"
;%include "glib.inc"
extern gtk_init
extern gtk_window_new
extern g_signal_connect_data
extern gtk_window_set_title
extern gtk_widget_show
extern gtk_main
extern gtk_main_quit
Build with:
yasm -felf64 -Worphan-labels -gdwarf2 thread-exit.asm &&
gcc -nostdlib -o thread-exit thread-exit.o $(pkg-config --libs gtk+-3.0)

Related

NASM x86-64: Why's my PC unable to run executable under Win64?

I created a small project under Win64 without any _printf from standard C library (on pure WinAPI). Code of the program below:
; ------------------------------------------------------------------------------ EXTERNS
extern GetStdHandle
extern WriteConsoleW
; ------------------------------------------------------------------------------ MACROSES
%define NULL 0
%define STD_OUTPUT_HANDLE -11
; ------------------------------------------------------------------------------ PROGRAM DATA
section .bss noexecute
hStdOut resq 1
chWritten resd 1
section .data noexecute
; wchar string!
msg dw __utf16__('Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї=Ї'), 10, 0
msg.sizeof equ ($-msg)
section .rodata noexecute
; ------------------------------------------------------------------------------ PROGRAM CODE
section .text
global __main
; prologue
__main: push rbp
mov rbp, rsp
; Get hStdOut to print in console
mov rcx, STD_OUTPUT_HANDLE
call GetStdHandle
mov qword [hStdOut], rax
mov rcx, rax
mov rdx, msg
mov r8, msg.sizeof
mov r9, chWritten
push NULL
call WriteConsoleW
; epilogue
pop rbp
exit0: xor rax, rax
ret
command:
nasm -fwin64 D:\Desktop\Roberto\asm_docs\files\myprog.asm -o myprog.exe
The error is a blue window that says:
Unable to run executable on your PC. To find a version for your computer, contact to developer of the application
No warnings during the preprocessing, compilation and linking.
Tried to run with -fwin32 replacing all r- registers on e- but still no effect...
What should i do? Thanks in advance!

How to use the monitor / mwait instructions in x86-64 assembly on Mac or baremetal

Originally I asked about umonitor and umwait, but it turns out as #harold suggested, that you can't even buy a processor that has those instructions yet. So this question is about monitor and mwait, because I am interested how to use those on baremetal.
I just learned of monitor/mwait.
I would have thought that there would be no evaluation of any instructions once mwait is called, so I don't understand how other parts of memory could be written to. Unless perhaps this is some multithreaded stuff with shared memory of some sort, which I don't fully think I understand.
Wondering if one could whip up a quick hello world program to demonstrate how to use these instructions. My attempt at it is this.
global _main
section .text
_main:
call print1
; watch when address 1000
; (randomly chosen)
; is written to.
mov eax, 1000
monitor eax
; wait for 100 ms, not sure
; or some interrupt
mov eax, 100
mwait eax
call print2
call exit
print2:
mov rdx, msg2.len
mov rsi, msg2
mov rdi, 1
mov rax, 0x2000004
syscall
ret
print1:
mov rdx, msg1.len
mov rsi, msg1
mov rdi, 1
mov rax, 0x2000004
syscall
ret
exit:
mov rdi, 0 ; exit status
mov rax, 0x2000001 ;: exit
syscall
section .data
msg1: db "start", 0xa, 0
.len: equ $ - msg1
msg2: db "end", 0xa, 0
.len: equ $ - msg2
What I'm wondering is what an example usage looks like for (a) a timespan like 100ms delay, and/or (b) an "event" of writing to a specific part of memory to trigger the callback, and/or (c) an external event like keyboard interrupt or ctrl+c interrupt if there is such a thing. Or perhaps the timing thing is done with tpause.
Trying the following with tpause I get error: invalid combination of opcode and operands:
mov eax, 1000
mov edx, 1000
mov rdi, 0
tpause rdi, edx, eax
The few resources I've found:
https://software.intel.com/sites/default/files/managed/c5/15/architecture-instruction-set-extensions-programming-reference.pdf
https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol3/o_fe12b1e2a880e0ce-303.html
https://software.intel.com/en-us/articles/how-to-use-the-monitor-and-mwait-streaming-simd-extensions-3-instructions
http://blog.andy.glew.ca/2010/11/httpsemipublic.html

How to include debug symbols in NASM code for debugging using GDB on Windows?

How to include debug symbols in NASM code for debugging using GDB on Windows?
Having coded some NASM assembly, I want to debug it using GDB.
I assemble and link using the following commands:
nasm -f win32 insertion_sort.asm
ld insertion_sort.obj
However, starting GDB (gdb a) yields:
Reading symbols from C:\Users\nze\Desktop\asm\sorting\insertion_sort\a.exe...(no debugging symbols found)...done.
In the code below I cannot reference _array like:
(gdb) x/4xw _array
No symbol table is loaded. Use the "file" command.
(gdb) x/4xw array
0x1: Cannot access memory at address 0x1
Also, setting breakpoint at _exit:
(gdb) break exit
Breakpoint 1 at 0x401464
(gdb) run
Starting program: C:\Users\nze\Desktop\asm\sorting\insertion_sort/insertion_sort.exe
[New Thread 5488.0x1c7c]
[New Thread 5488.0xc54]
[Inferior 1 (process 5488) exited with code 01]
causes GDB to just run the program to completion when run...
What is wrong?
The assembly code is:
BITS 32
section .data
_array: dd 4, 2, 8, 6, 1
_len: equ ($ - _array) / 4
section .text
global _start
_start:
push ebp
mov ebp, esp
xor ecx, ecx
_outer:
inc ecx
cmp ecx, _len
jge _exit
mov ebx, ecx
dec ebx
lea esi, [_array + ecx * 4]
lea edi, [_array + ebx * 4]
_inner:
cmp ebx, 0
jl _outer
mov eax, [edi]
cmp eax, [esi]
jle _outer
xchg eax, dword [esi] ; swap [esi] and [edi]
mov dword [edi], eax
sub esi, 4
sub edi, 4
dec ebx
jmp _inner
_exit:
mov esp, ebp
pop ebp
ret
have you tried include the debug information available for Windows (Codeview 8)?
$ nasm -gcv8 -f win32 -o insertion_sort.o insertion_sort.asm
$ gcc -m32 -o insertion_sort.exe insertion_sort.o

GDB disassembly uses inconsistent register naming

I'm debugging/disassembling a very simply C program I wrote just for learning purposes. However, I notice that GDB appears to be using inconsistent notation for the registers between the disassembled output and what it tells me when I enter "info registers" after a breakpoint.
Here is part of the disassembled output (around my breakpoint):
0x0000000100000d15 <main+181>: xor %dl,%dl
0x0000000100000d17 <main+183>: mov %ecx,%edi
0x0000000100000d19 <main+185>: mov %dl,%al
0x0000000100000d1b <main+187>: callq 0x100000da0 <checkLicense>
0x0000000100000d20 <main+192>: mov %eax,%ecx
0x0000000100000d22 <main+194>: cmp $0x0,%ecx
0x0000000100000d25 <main+197>: je 0x100000d47 <main+231>
0x0000000100000d27 <main+199>: lea 0x1bb(%rip),%rax # 0x100000ee9
0x0000000100000d2e <main+206>: mov %rax,%rdi
And here is part of the output I get when I call the "info registers" command in GDB:
(gdb) info registers
rax 0x1 1
rbx 0x0 0
rcx 0x1 1
rdx 0x1 1
rsi 0x3 3
rdi 0x3 3
I set my breakpoint where the cmp operation occurs. As you can see it is comparing the value in register ECX to 0, however, it doesn't appear that ECX is a real register. When I get the result of "info registers" it does appear to return real registers, namely rcx. When I try to manipulate the registers in GDB using "set $ecx = 1" for example, it has no effect, however when I do "set $rcx = 1", it does seem to work.
What's up with this inconsistency and is there a way to fix it?
What's up with this inconsistency?
The instruction cmp $0x0,%ecx compares lower 32-bits of register rcx with 0, so the disassembly is correct.
"info registers" it does appear to return real registers, namely rcx
Correct.
"set $ecx = 1" for example, it has no effect
It does have effect for me:
(gdb) info reg rcx
rcx 0xffffffffffffffff -1
(gdb) set $ecx = 0
(gdb) info reg rcx
rcx 0xffffffff00000000 -4294967296
If set $ecx = 1 really has no effect for you, it might be a GDB bug.

Printing argv[0] in nasm/Windows?

With online help, I was able to write nasm code in Mac OS X resulting in an executable that prints its own filename, argv[0] in equivalent C code. When I use the same code in Windows, I want it to print the programs name:
C:\> nasm -f win32 -o scriptname.obj scriptname.asm
C:\> golink /fo scriptname.exe scriptname.obj /console kernel32.dll Msvcrt.dll
GoLink.Exe Version 0.27.0.0 - Copyright Jeremy Gordon 2002/12 - JG#JGnet.co.uk
Output file: scriptname.exe
Format: win32 size: 2,048 bytes
C:\> scriptname.exe
Program: scriptname.exe
But what it actually prints is emptiness:
C:\> scriptname.exe
Program:
Specs:
golink 0.27.0.0
nasm 2.10.05
Windows 7 Professional x64
MacBook Pro 2009
You call GetStdHandle and save the returned value to ecx, ecx is a volatile register, the value will not be saved across calls unless you push/pop it. Your first call to WriteConsoleA uses it and clobbers it so the next call, ecx is not what you expect.
* EDIT *
I was bored so here is working code:
[bits 32]
section .data
program db "Program: ", 0
programlen equ $-program
nl db "", 13, 10, 0
nllen equ $-nl
section .bss
buf resd 1
argc resd 1
argv resb 255
section .text
global Start
extern GetStdHandle
extern __getmainargs
extern WriteConsoleA
extern ExitProcess
strlen: ; eax: a string ending in 0
push eax ; cache eax
.strloop:
mov bl, byte [eax]
cmp bl, 0
je .strret ; return len if bl == 0
inc eax ; else eax++
jmp .strloop
.strret:
pop ebx ; ebx = cached eax
sub eax, ebx ; eax -= ebx
ret ; eax = len
Start:
push 0
push buf
push argv
push argc
call __getmainargs
add esp, 16 ; clear stack (4 * 4 arguments)
push -11 ; get stdout
call GetStdHandle
mov esi, eax
add esp, 4 ; clear stack (4 * 1 argument)
push 0 ; null
push buf ; [chars written]
push programlen
push program
push esi ; stdout
call WriteConsoleA
add esp, 20 ; clear stack (4 * 5 arguments)
mov edx, [argv]
mov eax, [edx] ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
call strlen
push 0 ; null
push buf ; [chars written]
push eax ; len argv[0]
push dword [edx] ;<<<<<<<<<<<<<<<<<<<<<<<<<<<< ; argv[0]
push esi ; stdout
call WriteConsoleA
add esp, 20 ; clear stack (4 * 5 arguments)
push 0 ; null
push buf ; [chars written]
push nllen
push nl
push esi ; stdout
call WriteConsoleA
add esp, 20 ; clear stack (4 * 5 arguments)
push 0
call ExitProcess
D:\NASM Projects\ReadArgs>ReadArgs.exe
Program: ReadArgs.exe
D:\NASM Projects\ReadArgs>
The argc and argv arguments are for C based programs only. Assembly based programs are must use __getmainargs or __wgetmainargs functions from the C library to generate those variables like they are internally used by C based programs. See below MSDN article for details:
http://msdn.microsoft.com/en-us/library/ff770599.aspx
Well, yes and no. In Linux, at the _start: label, argc is at [esp] and argv[0] is at [esp + 4]. If your code works, this must also be true of Mac OSX. By doing -e main on the ld command line, essentially main is lying about its name. It isn't really a "C style main". This label is jumped to, not called. If main (or _main, for 'doze and Mac OSX) is called by "C startup code" (crt2.o), then there's a return address on the stack, so argc is at [esp + 4] and argv[0] is at [esp + 8]. Also, as Tim tells you at news:comp.lang.asm.x86 argv is a ** - a "pointer to pointer" - so you also need the mov ebx, [ebx] (a "de-reference"). I'm pretty sure in Windows, our code is called regardless of what we name the entrypoint. Can you get it to work that way?
EDIT: Well this has pretty much been beaten to death, and "solved"(?), but I got bored, too. This works in Linux, and "might" be portable.
; prints its own name (possibly portable?)
; nasm -f elf32 myprog.asm
; nasm -f macho myprog.asm --prefix _
; nasm -f win32 myprog.asm --prefix _
; gcc -o myprog myprog.o(bj) (-m32 for 64-bit systems)
global main
extern printf
section .data
prog db `Program: %s \n`, 0
section .text
main:
mov eax, [esp + 8]
mov eax, [eax]
push eax
push prog
call printf
add esp, 4 * 2
ret
;----------------------

Resources