Article by Ayman Alheraki in February 2 2025 06:40 AM
In modern operating systems like Windows, Linux, and macOS, which operate in Protected Mode, direct access to hardware components—such as the graphics card—is not allowed for security and stability reasons. Unlike DOS, where programs could manipulate the video memory directly, modern OSes enforce strict access control. However, it is still possible to render graphics without using external libraries like DirectX or OpenGL, albeit with some complexities. This article explores alternative methods for rendering graphics using Assembly.
Protected Mode:
Prevents direct access to memory or hardware (e.g., video card) without the operating system’s permission.
Windowing System:
Graphics rendering is managed through OS-level APIs (e.g., GDI in Windows or X11 in Linux).
Abstraction Layers:
Programs must interact with low-level system interfaces provided by the OS.
Linux provides a Framebuffer Device (/dev/fb0
), which allows direct access to video memory if supported by the kernel and hardware.
Open the framebuffer device:
int fb = open("/dev/fb0", O_RDWR);
Retrieve screen information (resolution, color depth, etc.) using ioctl
with FBIOGET_VSCREENINFO
.
Map video memory to the program’s address space using mmap
.
Write pixel data directly to the allocated memory.
xxxxxxxxxx
section .data
fb_device db '/dev/fb0', 0
section .text
global _start
_start:
; Open the framebuffer device
mov rax, 2 ; sys_open syscall
mov rdi, fb_device
mov rsi, 2 ; O_RDWR
syscall
; Use ioctl and mmap to access framebuffer memory
; ... (detailed implementation depends on framebuffer structure)
Requires root privileges or membership in the video
group.
Pixel format (RGB/BGR) varies depending on hardware.
Performance may not be optimal compared to hardware-accelerated methods.
On Windows, direct access to video memory is heavily restricted. However, simple pixel manipulation can be done via GDI functions like GetDC()
and SetPixel()
.
xxxxxxxxxx
extern GetDC
extern SetPixel
extern ExitProcess
section .text
global _start
_start:
; Get the device context for the desktop window
push 0
call GetDC
; Draw a red pixel at (100,100)
push 0x0000FF ; RGB color (Red)
push 100 ; Y coordinate
push 100 ; X coordinate
push eax ; Device Context (DC)
call SetPixel
; Exit the program
call ExitProcess
Slow performance compared to direct memory access.
Requires linking with Windows system libraries (user32.dll
).
Direct access to physical video memory is nearly impossible without writing a Kernel-Mode Driver, which requires digital signing and is highly complex.
On macOS, direct hardware access is even more restricted than on Linux or Windows. The system relies on Quartz Compositor and Core Graphics for rendering. Unlike Linux’s /dev/fb0
, macOS does not expose a direct framebuffer device for user-space applications.
Strict security policies prevent direct access to GPU memory.
No publicly available framebuffer device.
The only viable way to draw pixels is via Quartz/Core Graphics APIs, which require Objective-C or C bindings rather than raw Assembly.
Memory Management:
Proper memory mapping and understanding pixel formats (32-bit ARGB, RGB/BGR variations) are required.
Performance Issues:
Direct pixel manipulation is significantly slower than hardware-accelerated methods (e.g., OpenGL).
Compatibility:
Hardware differences necessitate dynamic configuration, making universal implementations difficult.
For Modern Applications:
Using libraries like SDL2, OpenGL, or Vulkan is much more efficient and practical, even when working with Assembly.
Exceptions:
Direct framebuffer manipulation is useful in embedded systems or when developing an operating system kernel.
Rendering graphics in Assembly on modern operating systems requires interacting with system APIs instead of direct hardware access. In Linux, the framebuffer device (/dev/fb0
) provides a way to manipulate pixels, but it comes with security and compatibility constraints. In Windows, GDI allows simple pixel drawing, though it is inefficient. In macOS, strict security measures make direct manipulation nearly impossible.
For most practical applications, using high-level graphics libraries remains the best approach, while direct memory access is only relevant for low-level system programming or specialized environments.