Wednesday, 19 October 2011

X86 assembly with GAS on Windows

I've been reading "Professional Assembly Language" by Richard Blum. The book gives a good overview of Intel architecture and takes you through from very basic samples. The sample assembly programs in the book assume you are on Linux and are using the gnu assembler however it is simple enough to get working on Windows. I do have a Linux box but I wanted to try the sample programs on my laptop which is Windows 7 (I couldn't get Ubuntu stable, too much hassle with the WiFi card and also the battery life is way better with Windows). Firstly download MinGW from:

http://www.mingw.org/

This will provide you with the Gnu Assembler (as.exe under MinGW\bin). Now most of the samples will run fine up-to the last part where they try to output to console. The book gives the following instructions to output a string:

movl $4, %eax
movl $1, %ebx
movl $output, %ecx
movl $42, %edx
int $0x80.

This is from Page 80 of the book. EAX contains the system call value, EBX is the file descriptor to write to, ECX is the start of the string and EDX is the length. Now to do the same on Windows we are going to utilise a Win32 system call from the kernel32.dll:


pushl $-11
call _GetStdHandle@4
mov %eax, handle
pushl $0
pushl $written
pushl $42
pushl $output
pushl handle
call _WriteConsoleA@20


pushl $0
call _ExitProcess@4

This is equivalent to the following C code:


handle = GetStdHandle(-11);
WriteConsole(handle, &msg[0], 13, &written, 0);
ExitProcess(0);

I got the above from this site http://www.cs.lmu.edu/~ray/notes/x86assembly/. Its a very useful page showing you how to call C libraries / system calls on Windows and Linux.

I will now apply the above to a sample from the book. The sample program on page 77 will call the CPUID instruction and output the result. The code below is the same as the sample bar the final output. To build this you need to link in the kernel32.dll by issuing the ld command after calling the assembler:


as -o cpuid.o cpuid.s
ld -o cpuid.exe cpuid.o -lkernel32

Contents of cpuid.s:

.section .data

output:
  .ascii "The processor vendor ID is 'xxxxxxxxxxxxx'\n"
handle: .int 0
written: .int 0


.section .text
.globl _start
_start:
  movl $0, %eax
  cpuid
  movl $output, %edi
  movl %ebx, 28(%edi)
  movl %edx, 32(%edi)
  movl %ecx, 36(%edi)
  pushl $-11
  call _GetStdHandle@4
  mov %eax, handle
  pushl $0
  pushl $written
  pushl $42
  pushl $output
  pushl handle
  call _WriteConsoleA@20


  pushl $0
  call _ExitProcess@4

1 comment:

  1. How did you get to know the windows system calls and how to properly call them? Masm uses INVOKE and ten it is hidden how it is called on the low level. Do you have a reference manual? Please share. I want to use gas for windows but can't do much without proper system calls.

    ReplyDelete