How to show a picture on the screen with assembly on Linux? - linux

I want to make a game in Linux assembly. Is there a way to show (or draw) a picture on the screen via Linux kernel system calls?
I searched for it, but all the results that I get is about DOS assembly language.

It's possible to do, but it seems like an incredibly tedious and slow way to develop software in assembly these days.
Assuming you're running on an i386 platform (the syscall ABI is different for each platform), look at uClibcs libc/sysdeps/linux/i386/syscall.S:
.text
.global syscall
.type syscall,%function
syscall:
pushl %ebp
pushl %edi
pushl %esi
pushl %ebx
movl 44(%esp),%ebp /* Load the 6 syscall argument registers */
movl 40(%esp),%edi
movl 36(%esp),%esi
movl 32(%esp),%edx
movl 28(%esp),%ecx
movl 24(%esp),%ebx
movl 20(%esp),%eax /* Load syscall number into %eax. */
int $0x80
popl %ebx
popl %esi
popl %edi
popl %ebp
cmpl $-4095,%eax
jae __syscall_error
ret /* Return to caller. */
.size syscall,.-syscall
This assumes all of the syscall arguments, as well as the syscall number have been loaded on the stack.
You can find the syscall numbers in the Linux kernels include/asm-generic/unistd.h file.
Now that you know how to call system calls from assembly you still need to know which system calls to call of course. I'd suggest reading up on the Linux Framebuffer. Interacting with X is going to be even more complicated.

If you want to use kernel functions only, you must take the vesa framebuffer: Using the framebuffer device under Linux. Have fun =)

I used to write stuff in assembler as a hobbyist when I was kid. Now I regard it as much too slow and unportable - surely you want your game to run on an ARM-based phone too? But assembly doesn't really give you that unless you completely rewrite the program after writing it for x86 and perhaps x86-64.
If you really want to do assembler, you'll probably find that your biggest hurdle is figuring out how to call the various C-API functions required, because almost everything on Linux uses a C API at one level or another. The best way to deal with that is probably to write a tiny C program that does what you need, and then compile it with:
gcc -S t.c
This should give you assembler for something similar to what you need to do, in a file named t.s.

Related

Assistance on x86 Assembler running on Linux

I am currently learning a bit of Assembler on Linux and I need your advice.
Here is the small program:
.section .data
zahlen:
.float 12,44,5,143,223,55,0
.section .text
.global _start
_start:
movl $0, %edi
movl zahlen (,%edi,4), %eax
movl %eax, %ebx
begin_loop:
cmpl $0, %eax
je prog_end
incl %edi
movl zahlen (,%edi,4), %eax
cmpl %ebx, %eax
jle begin_loop
movl %eax, %ebx
jmp begin_loop
prog_end:
movl $1, %eax
int $0x80
The program seems to compiling and running fine.
But I have some unclear questions/behaviors:
if I check the return value, which is the highers number in register %ebx, with the command "echo %?" it always return 0. I expect the value 223.
Any Idea why this happens?
I checked with DDD and gdb compiling with debugging option. So i saw that the program runs the correct steps.
But if i want to exam the register with command ie. "i r eax" it only shows me the address i believe, not the value. Same on DDD. I see only registers rax rbx and so on.
Here i need some advise to get on the right track.
Any Help appreciated.
Thanks
The "main" registers eax, ebx, ecx, edx, etc. are all designed to work with integers only. A float is a shorthand term that typically refers to a very specific data format (namely, the IEEE-754 binary32 standard), for which your CPU has dedicated registers and hardware to work with. As you saw, you are allowed to load them into integer registers as-is, but the value isn't going to convert itself like it would in a high-level, dynamically-typed language. Your code loaded the raw bit pattern instead, which likely is not at all what you intended.
This is because assembly has no type safety or runtime type-checking. The CPU has no knowledge of what type you declared your data as in your program. So when loading from memory into eax the CPU assumes that the data is a 32-bit integer, even if you declared it in your source code as something else.
If you're curious as to what a float actually looks like you can check this out: Floating Point to Hex Calculator
Switching from float to long solved the problem. Think mistake by myself. Also compiling and linking as 32bit shows the right registers in the debugger.

"Segmentation fault", x86_64 assembly, AT&T syntax

I am running my code in a 64-bit Linux environment where the Linux Kernel is built with IA32_EMULATION and X86_X32 disabled.
In the book Programming from the Ground Up the very first program doesn't do anything except produce a segfault:
.section .data
.section .text
.globl _start
_start:
movl $1, %eax
movl $0, %ebx
int $0x80
I convert the code to use x86-64 instructions but it also segfaults:
.section .data
.section .text
.globl _start
_start:
movq $1, %rax
movq $0, %rbx
int $0x80
I assembled both these programs like this:
as exit.s -o exit.o
ld exit.o -o exit
Running ./exit gives Segmentation fault for both. What am I doing wrong?
P.S. I have seen a lot of tutorials assembling code with gcc, however I'd like to use gas.
Update
Combining comments and the answer, here's the final version of the code:
.section .data
.section .text
.globl _start
_start:
movq $60, %rax
xor %rbx, %rbx
syscall
int $0x80 is the 32bit ABI. On normal kernels (compiled with IA32 emulation), it's available in 64bit processes, but you shouldn't use it because it only supports 32bit pointers, and some structs have a different layout.
See the x86 tag wiki for info on making 64bit Linux system calls. (Also ZX485's answer on this question). There are many differences, including the fact that the syscall instruction clobbers %rcx and %r11, unlike the int $0x80 ABI.
In a kernel without IA32 emulation, like yours, running int $0x80 is probably the same as running any other invalid software interrupt, like int $0x79. Single-stepping that instruction in gdb (on my 64bit 4.2 kernel that does include IA32 emulation) results in a segfault on that instruction.
It doesn't return and keep executing garbage bytes as instructions (which would also result in a SIGSEGV or SIGILL), or keep executing until it jumped to (or reached normally) an unmapped page. If it did, that would be the mechanism for segfaulting.
You can run a process under strace, e.g. strace /bin/true --version to make sure it's making the system calls you thought it would. You can also use gdb to see where a program segfaults. Using a debugger is essential, moreso than in most languages, because the failure mode in asm is usually just a segfault.
The first observation is that the code in both your examples effectively do the same thing, but are encoded differently. The site x86-64.org has some good information for those starting out with x86-64 development. The first code snippet that uses 32-bit registers is equivalent to the second because of Implicit Zero Extend:
Implicit zero extend
Results of 32-bit operations are implicitly zero extended to 64-bit values. This differs from 16 and 8 bit operations, that don't affect the upper part of registers. This can be used for code size optimisations in some cases, such as:
movl $1, %eax # one byte shorter movq $1, %rax
xorq %rax, %rax # three byte equivalent of mov $0,%rax
andl $5, %eax # equivalent for andq $5, %eax
The question is, why does this code segfault? If you had run this code on a typical x86-64 Linux distro your code may have exited as expected without generating a segfault. The reason that your code is failing is because you are using a custom kernel with IA32 emulation off.
IA32 emulation in the Linux kernel does allow you to use the 32-bit int 0x80 interrupt to make calls using the traditional 32-bit system call mechanism. This is an emulation layer, and doesn't support passing pointers that can't be represented in a 32-bit register. This is the case for stack based pointers since they fall outside the 4gb address space, and can't be accessed with 32-bit pointers.
Your system has IA32 emulation off, and because of that int 0x80 doesn't exist for backwards compatibility. The result is that the int 0x80 interrupt will throw a segmentation fault and your application will fail.
In x86-64 code it is preferred that you use the syscall instruction to make system calls to the 64-bit Linux kernel. This mechanism supports 64-bit operands and pointers where necessary. Ryan Chapman's site has some good information on the 64-bit SYSCALL interface which differs considerably from the 32-bit int 0x80 mechanism.
Your code could have been written this way to work in a 64-bit environment without IA32 emulation:
.section .text
.globl _start
_start:
mov $60, %eax
xor %ebx, %ebx
syscall
Other useful information on doing 64-bit development can be found in the 64-bit System V ABI. This document also better describes the general syscall convention used by the Linux kernel including side effects in Section A.2 . This document is also very informative if you also wish to interface with third party libraries and modules (like the C library etc).
The reason is that the Linux System Call Table for x86_64 is different from the table for x86.
In x86, SYS_EXIT is 1. In x64, SYS_EXIT is 60 and 1 is the value for SYS_WRITE, which, if called, expects a const char *buf in %RSI. If that buffer pointer is invalid, it probably segfaults.
%rax System call %rdi %rsi %rdx %r10 %r8 %r9
1 sys_write unsigned int fd const char *buf size_t
60 sys_exit int error_code

Linux sbrk() as a syscall in assembly

So, as a challenge, and for performance, I'm writing a simple server in assembly. The only way I know of is via system calls. (through int 0x80) Obviously, I'm going to need more memory than allocated at assemble, or at load, so I read up and decided I wanted to use sbrk(), mainly because I don't understand mmap() :p
At any rate, Linux provides no interrupt for sbrk(), only brk().
So... how do I find the current program break to use brk()? I thought about using getrlimit(), but I don't know how to get a resource (the process id I'd guess) to pass to getrlimit(). Or should I find some other way to implement sbrk()?
The sbrk function can be implemented by getting the current value and subtracting the desired amount manually. Some systems allow you to get the current value with brk(0), others keep track of it in a variable [which is initialized with the address of _end, which is set up by the linker to point to the initial break value].
This is a very platform-specific thing, so YMMV.
EDIT: On linux:
However, the actual Linux system call returns the new program break on success. On failure, the system call returns the current break. The glibc wrapper function does some work (i.e., checks whether the new break is less than addr) to provide the 0 and -1 return values described above.
So from assembly, you can call it with an absurd value like 0 or -1 to get the current value.
Be aware that you cannot "free" memory allocated via brk - you may want to just link in a malloc function written in C. Calling C functions from assembly isn't hard.
Source:
#include <unistd.h>
#define SOME_NUMBER 8
int main() {
void *ptr = sbrk(8);
return 0;
}
Compile using with Assembly Output option
gcc -S -o test.S test.c
Then look at the ASM code
_main:
Leh_func_begin1:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
subq $16, %rsp
Ltmp2:
movl $8, %eax
movl %eax, %edi
callq _sbrk
movq %rax, -16(%rbp)
movl $0, -8(%rbp)
movl -8(%rbp), %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
addq $16, %rsp
popq %rbp
ret
Leh_func_end1:
There is no system call for it but you should be able to still make the call

Conditional move problem

Code fragment from Assembly exercise (GNU Assembler, Linux 32 bit)
.data
more:
.asciz "more\n"
.text
...
movl $more, %eax # this is compiled
cmova more, %eax # this is compiled
cmova $more, %eax # this is not compiled
Error: suffix or operands invalid for `cmova'
I can place string address to %eax using movl, but cmova is not compiled. I need the source operand to be $more and not more, to use it for printing. Finally, this value goes to %ecx register of Linux system call 4 (write).
The assembler is correct! The CMOVcc instructions are more limited than MOV: they can only move 16/32/64-bit values from memory into a register, or from one register to another. They don't support immediate (or 8-bit register) operands.
(Reference: http://www.intel.com/Assets/PDF/manual/253666.pdf - from the set of manuals available at http://www.intel.com/products/processor/manuals/index.htm .)

How does a syscall actually happen on linux?

Inspired by this question
How can I force GDB to disassemble?
and related to this one
What is INT 21h?
How does an actually system call happen under linux? what happens when the call is performed, until the actual kernel routine is invoked ?
Assuming we're talking about x86:
The ID of the system call is deposited into the EAX register
Any arguments required by the system call are deposited into the locations dictated by the system call. For example, some system calls expect their argument to reside in the EBX register. Others may expect their argument to be sitting on the top of the stack.
An INT 0x80 interrupt is invoked.
The Linux kernel services the system call identified by the ID in the EAX register, depositing any results in pre-determined locations.
The calling code makes use of any results.
I may be a bit rusty at this, it's been a few years...
The given answers are correct but I would like to add that there are more mechanisms to enter kernel mode. Every recent kernel maps the "vsyscall" page in every process' address space. It contains little more than the most efficient syscall trap method.
For example on a regular 32 bit system it could contain:
0xffffe000: int $0x80
0xffffe002: ret
But on my 64-bitsystem I have access to the way more efficient method using the syscall/sysenter instructions
0xffffe000: push %ecx
0xffffe001: push %edx
0xffffe002: push %ebp
0xffffe003: mov %esp,%ebp
0xffffe005: sysenter
0xffffe007: nop
0xffffe008: nop
0xffffe009: nop
0xffffe00a: nop
0xffffe00b: nop
0xffffe00c: nop
0xffffe00d: nop
0xffffe00e: jmp 0xffffe003
0xffffe010: pop %ebp
0xffffe011: pop %edx
0xffffe012: pop %ecx
0xffffe013: ret
This vsyscall page also maps some systemcalls that can be done without a context switch. I know certain gettimeofday, time and getcpu are mapped there, but I imagine getpid could fit in there just as well.
This is already answered at
How is the system call in Linux implemented?
Probably did not match with this question because of the differing "syscall" term usage.
Basically, its very simple: Somewhere in memory lies a table where each syscall number and the address of the corresponding handler is stored (see http://lxr.linux.no/linux+v2.6.30/arch/x86/kernel/syscall_table_32.S for the x86 version)
The INT 0x80 interrupt handler then just takes the arguments out of the registers, puts them on the (kernel) stack, and calls the appropriate syscall handler.

Resources