0

I was trying to create an empty window using X11 and managed to do so with the following C:

#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>

Display *display;
Window window;
XEvent event;
int screen;

int main(void) {
    display = XOpenDisplay(NULL);
    if (display == NULL) {
        perror("Cannot open display\n");
        exit(1);
    }

    screen = DefaultScreen(display);
    window = XCreateSimpleWindow(display, RootWindow(display, screen), 10, 10, 500, 500, 1, BlackPixel(display, screen), WhitePixel(display, screen));

    // Interested in the delete window message
    Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
    XSetWMProtocols(display, window, &wm_delete_window, 1);

    // Select events
    XSelectInput(display, window, ExposureMask | KeyPressMask);
    // Show window
    XMapWindow(display, window);

    while (1) {
        XNextEvent(display, &event);

        if (event.type == ClientMessage && event.xclient.data.l[0] == wm_delete_window) {
            break;
        }
    }

    // Cleanup
    XCloseDisplay(display);

    return 0;
}

However, I would like to learn assembly and how to interface it with C, so I started to recreate it line-by-line:

global _start

;
; EXTERNAL SYMBOLS (X11)
;
extern XOpenDisplay

;
; CONSTANTS
;
SYS_WRITE   equ 1
SYS_EXIT    equ 60
STDOUT      equ 1

;
; DATA - Initialized data
;
SECTION .data
msg     db "Hello, World!", 10
msg_len equ $-msg

;
; BSS - Uninitialized data
;
section .bss
    display resq 1 ; Reserve space for a 64-bit pointer
    window resq 1  ; Reserve space for a 64-bit pointer
    event resb 24  ; Reserve space for an XEvent, which is typically 24 bytes
    screen resd 1  ; Reserve space for a 32-bit integer

;
; TEXT - Code
;
SECTION .text
_start:
    xor rdi, rdi ; NULL
    call XOpenDisplay
    mov [display], rax ; return value in RAX

    ; Hello world, because why not
    mov rax, SYS_WRITE
    mov rdi, STDOUT
    mov rsi, msg
    mov rdx, msg_len
    syscall

    ; Exit
    mov rax, SYS_EXIT
    mov rdi, 0
    syscall

I compile both projects with the same Makefile using run_c and run_asm, respectively:

C_TARGET := c
ASM_TARGET := asm
BUILD_DIR := build
CC := gcc
ASM := nasm
LD := ld
LDFLAGS := -lX11
DEBUGFLAGS = -g
RELEASEFLAGS = -O3

.PHONY: run_asm run_c clean

$(BUILD_DIR)/$(ASM_TARGET): $(BUILD_DIR)/$(ASM_TARGET).o
    $(LD) -o $@ $< $(LDFLAGS)

$(BUILD_DIR)/$(ASM_TARGET).o: main.asm | $(BUILD_DIR)
    $(ASM) -f elf64 $< -o $@ $(DEBUGFLAGS)

$(BUILD_DIR)/$(C_TARGET): main.c | $(BUILD_DIR)
    $(CC) -o $@ $< $(LDFLAGS) $(DEBUGFLAGS)

$(BUILD_DIR):
    mkdir -p $@

run_asm: $(BUILD_DIR)/$(ASM_TARGET)
    $(BUILD_DIR)/$(ASM_TARGET)

run_c: $(BUILD_DIR)/$(C_TARGET)
    $(BUILD_DIR)/$(C_TARGET)

clean:
    rm -rf $(BUILD_DIR)

The C compiles, links, and runs, but the assembly doesn't. It compiles and links, but when I attempt to run it using make run_asm, I get the following error:

make: build/asm: No such file or directory

The binary is in the correct place, and it doesn't work when I run it directly from the command line. I thought it might be a file permissions problem, so I added this line to the $(BUILD_DIR)/$(ASM_TARGET) rule:

chmod +x $@

This did nothing, as the file has -rwxr-xr-x permissions with or without the chmod. I'm new to nasm and assembly and would greatly appreciate any help.

NaniNoni
  • 155
  • 11

0 Answers0