I'm actually writing this code as inline ASM but I feel it is more relevant to ASM than it is to C...

Basically all I want to do for now is print the alphabet. However I'm having some trouble getting used to AT&T syntax (I would rather learn it than keep just using Intel syntax) and I'm also unsure as to how to solve this segfault I'm getting:

#include <stdio.h>

int main() {
    // code
    {
        asm volatile("movb %ah, 0x4C\n" /* BIOS interrupt call for output */
            "movb $'A', %AL\n"          /* Place "A" in AL                */
            "jmp start\n"
            "start:\n\t"
                "add $1, %AL\n\t"   /* Add 1 to 'A' to move on to 'B', etc. */
                "print:\n\t\t"
                    "int $0x21\n\t" /* Print contents of AL */
              #if 0
                "hlt\n"       /* Halt the machine (commented out because I think I need ring 0 access to use hlt) */
              : " %ax", "%bx" /* List of registers used (commented out because GCC complained of the comma)       */
              #endif
            );
    }
    // code
    return 0;
}

I have tried without the "volatile" keyword. I did nothing, as I expected...

Thank you :)

Recommended Answers

All 10 Replies

I'm actually writing this code as inline ASM but I feel it is more relevant to ASM than it is to C...

Basically all I want to do for now is print the alphabet. However I'm having some trouble getting used to AT&T syntax (I would rather learn it than keep just using Intel syntax) and I'm also unsure as to how to solve this segfault I'm getting:

#include <stdio.h>

int main() {
    // code
    {
        asm volatile("movb %ah, 0x4C\n" /* BIOS interrupt call for output */
            "movb $'A', %AL\n"          /* Place "A" in AL                */
            "jmp start\n"
            "start:\n\t"
                "add $1, %AL\n\t"   /* Add 1 to 'A' to move on to 'B', etc. */
                "print:\n\t\t"
                    "int $0x21\n\t" /* Print contents of AL */
              #if 0
                "hlt\n"       /* Halt the machine (commented out because I think I need ring 0 access to use hlt) */
              : " %ax", "%bx" /* List of registers used (commented out because GCC complained of the comma)       */
              #endif
            );
    }
    // code
    return 0;
}

I have tried without the "volatile" keyword. I did nothing, as I expected...

Thank you :)

Your seg fault is probably from this line

movb %ah, 0x4C\n

Your moving the contents of ah into memory address 0x4c

Are you writing this for Linux or Windows?

Your seg fault is probably from this line

movb %ah, 0x4C\n

Your moving the contents of ah into memory address 0x4c

AHHH! Drat! The first tutorial I ever read was in Intel syntax; so as I say I'm likely to make many mistakes in AT&T syntax. I think, however, that it is probably better to write AT&T -- when you learn it I think it's more explicit -- you can easily see what are variables, what is in hex, and what is being used as a register.

Thank you :)

Are you writing this for Linux or Windows?

Linux.

I just figured out why the list of registers didn't work. You're meant to put %% where you use them instead of a singe %; as per this article http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s5

Do you know if I need ring 0 access to use halt? I would assume so because IIRC it hangs the machine; and obviously you don't want me running code on your machine that halts execution :P

Thanks.

AHHH! Drat! The first tutorial I ever read was in Intel syntax; so as I say I'm likely to make many mistakes in AT&T syntax. I think, however, that it is probably better to write AT&T -- when you learn it I think it's more explicit -- you can easily see what are variables, what is in hex, and what is being used as a register.

Thank you :)


Linux.

I just figured out why the list of registers didn't work. You're meant to put %% where you use them instead of a singe %; as per this article http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s5

Do you know if I need ring 0 access to use halt? I would assume so because IIRC it hangs the machine; and obviously you don't want me running code on your machine that halts execution :P

Thanks.

If your going to be messing around with assembly system programming then you should download the Intel or AMD manuals, they have explanations for all the opcodes..

If your going to be messing around with assembly system programming

Yes, I will be, but not for a while. I just wanted to play with hlt. And by a while I mean a few years. I'm nowhere near that level yet.

you should download the Intel or AMD manuals, they have explanations for all the opcodes..

Oh, thanks :-)

I have decided to try this in a plain asm file using as and ld;

.intel_syntax noprefix

.globl _start

_start:  
    mov ah, 0x4C
    mov al, 'A'

    abc:
        nextletter:
            add ah, 1
        print:
            int 0x21

I don't understand where I'm getting a segfault.
I thought it was because of my use of AT&T syntax and not knowing it properly; so I tried with intel syntax and it didn't help :l

Does anyone know where the segfault is?

Thanks :l

If this is for linux, why are you using int 21. shouldn't you be using

movl	$4, %eax
movl	$1, %ebx
movl	pointer to whatever you want to print, %ecx
movl	len of what you want to print, %edx
int $0x80

Try this code...I'm not sure if your running a 32 or 64 bit box...

#include <stdio.h>
#include <stdlib.h>

void printit(char *chr)
{
	//64 bit
	__asm__ __volatile__
	(
	 	"movq	$1, %%rax\n\t"
		"movq	$1, %%rdi\n\t"	
		"movq	%0, %%rsi\n\t"
		"movq	$1, %%rdx\n\t"
		"syscall\n\t"
		:"=m"(chr)
	);
	//32 bit - Note untested
	//__asm__ __volatile__
	//(
	//	"movl	$4, %%eax\n\t"
	//       	"movl	$1, %%ebx\n\t"
	//	"movl	%0, %%ecx\n\t"
	//	"movl	$1, %%edx\n\t"
	//	"int	$0x80\n\t"
	//	:"=m"(chr)	
	//);
}

int main(int argc, char**argv)
{
	char ch = 0x61;
	int i = 0;

	for (i = 0; i < 26; ++i)
	{
		printit(&ch);
		++ch;
	}
	exit(EXIT_SUCCESS);
}

Try this code...I'm not sure if your running a 32 or 64 bit box...

#include <stdio.h>
#include <stdlib.h>

void printit(char *chr)
{
	//64 bit
	__asm__ __volatile__
	(
	 	"movq	$1, %%rax\n\t"
		"movq	$1, %%rdi\n\t"	
		"movq	%0, %%rsi\n\t"
		"movq	$1, %%rdx\n\t"
		"syscall\n\t"
		:"=m"(chr)
	);
	//32 bit - Note untested
	//__asm__ __volatile__
	//(
	//	"movl	$4, %%eax\n\t"
	//       	"movl	$1, %%ebx\n\t"
	//	"movl	%0, %%ecx\n\t"
	//	"movl	$1, %%edx\n\t"
	//	"int	$0x80\n\t"
	//	:"=m"(chr)	
	//);
}

int main(int argc, char**argv)
{
	char ch = 0x61;
	int i = 0;

	for (i = 0; i < 26; ++i)
	{
		printit(&ch);
		++ch;
	}
	exit(EXIT_SUCCESS);
}

I'm using x86_64 so yes, 64-bit.
And thanks :) that does work.
I'll play around with that now.

I almost forgot to tell you, if your using 64 bit linux assembly programming then most of the books and tuts out there are out dated...The ABI(application binary interface) for Linux 64 bit programs are different than the 32 bit ABI...Below is an excerpt from the Entry_64.S file from a 64 bit kernel source...Please note the order that registers are pasted data for a system call...You'll see I used this order in the 64 bit code above

%rax
%rdi
%rsi
%rdx
%r10
%r8
%r9
%r11

/*
 * System call entry. Upto 6 arguments in registers are supported.
 *
 * SYSCALL does not save anything on the stack and does not change the
 * stack pointer.
 */

/*
 * Register setup:
 * rax  system call number
 * rdi  arg0
 * rcx  return address for syscall/sysret, C arg3
 * rsi  arg1
 * rdx  arg2
 * r10  arg3 	(--> moved to rcx for C)
 * r8   arg4
 * r9   arg5
 * r11  eflags for syscall/sysret, temporary for C
 * r12-r15,rbp,rbx saved by C code, not touched.
 *
 * Interrupts are off on entry.
 * Only called from user space.
 *
 * XXX	if we had a free scratch register we could save the RSP into the stack frame
 *      and report it properly in ps. Unfortunately we haven't.
 *
 * When user can change the frames always force IRET. That is because
 * it deals with uncanonical addresses better. SYSRET has trouble
 * with them due to bugs in both AMD and Intel CPUs.
 */

I almost forgot to tell you, if your using 64 bit linux assembly programming then most of the books and tuts out there are out dated...The ABI(application binary interface) for Linux 64 bit programs are different than the 32 bit ABI...Below is an excerpt from the Entry_64.S file from a 64 bit kernel source...Please note the order that registers are pasted data for a system call...You'll see I used this order in the 64 bit code above

%rax
%rdi
%rsi
%rdx
%r10
%r8
%r9
%r11

/*
 * System call entry. Upto 6 arguments in registers are supported.
 *
 * SYSCALL does not save anything on the stack and does not change the
 * stack pointer.
 */

/*
 * Register setup:
 * rax  system call number
 * rdi  arg0
 * rcx  return address for syscall/sysret, C arg3
 * rsi  arg1
 * rdx  arg2
 * r10  arg3 	(--> moved to rcx for C)
 * r8   arg4
 * r9   arg5
 * r11  eflags for syscall/sysret, temporary for C
 * r12-r15,rbp,rbx saved by C code, not touched.
 *
 * Interrupts are off on entry.
 * Only called from user space.
 *
 * XXX	if we had a free scratch register we could save the RSP into the stack frame
 *      and report it properly in ps. Unfortunately we haven't.
 *
 * When user can change the frames always force IRET. That is because
 * it deals with uncanonical addresses better. SYSRET has trouble
 * with them due to bugs in both AMD and Intel CPUs.
 */

I'll bear that in mind, thanks :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.