3

I am new to assembly programming and am having trouble printing a character to the screen. Every time I execute my program I get a segmentation fault and I am not sure why.

.section .data
  A:
    .long  65  # ascii code for 'A'

.section .text
.globl _start

_start:
 movl $1, %edx # length of character to print, 1
 movl  A, %ecx # what I want printed
 movl $1, %ebx # file descriptor for STDOUT
 movl $4, %eax # syscall number for sys_write

 int $0x80     # calls kernel

 movl $0, %ebx # return status
 movl $1, %eax # syscall number for sys_exit

 int $0x80     # calls kernel

These are the commands I use to build (my file is named write.s)

as write.s -o write.o
ld write.o -o write

Is this not the correct way to print a character? Any help would be appreciated.

Hunter McMillen
  • 59,865
  • 24
  • 119
  • 170
  • How are you assembling/linking this ? Note that it needs to be a 32 bit executable. – Paul R Aug 31 '12 at 16:22
  • I am using the linux's standard assembler and linking. I will add the commands above because they are important. The `file` command lists my executable as a 32-bit ELF file. – Hunter McMillen Aug 31 '12 at 16:24
  • 1
    Have you used a debugger to check if the arguments are set up correctly? – Niklas B. Aug 31 '12 at 16:31
  • For some reason I was expecting `movl` to load the address since A is an address. But `leal` did the job. Would you mind making this an answer and also could you point me to a debugger I can use for assembly? @NiklasB. – Hunter McMillen Aug 31 '12 at 16:34
  • Did you read the http://tldp.org/HOWTO/Assembly-HOWTO/ ? Did you `strace` your program? – Basile Starynkevitch Aug 31 '12 at 16:43
  • @BasileStarynkevitch No I have been following a book called 'Programming from the Group Up', but I will definitely look at that. Thanks – Hunter McMillen Aug 31 '12 at 16:54

1 Answers1

2
movl A, %ecx

means: Copy the value at the address of the label A into %ecx. The correct instruction would be:

movl $A, %ecx

or

leal A, %ecx

You can use GDB for debugging in these cases (note that you have to assemble with the -g flag to get debug information):

$ as -g write.s -o write.o
$ ld write.o -o write
$ gdb write
GNU gdb (GDB) 7.5
   [.. snip ..]
(gdb) b test.s:13
Breakpoint 1 at 0x4000c6: file test.s, line 13.
(gdb) run
Starting program: /home/niklas/tmp/asm/write 

Breakpoint 1, _start () at test.s:13
13   int $0x80     # calls kernel
(gdb) info registers ecx
ecx            0x41 65

As you see, %ecx has the integer value 65, which is not what you want.


If you run strace ./write, it will decode the system call args and return value for you. You'll see that write() just returns -EFAULT without doing anything else when you pass it a bad pointer.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Niklas B.
  • 92,950
  • 18
  • 194
  • 224
  • Do you know how I could print a value that isn't in the data region? like if I just wanted to print the letter 'A' using its ascii code 65. Is there anyway to load immediate values? – Hunter McMillen Aug 31 '12 at 18:28
  • @Hunter: You can put it on the stack: `pushl $0x41 # movl %esp, %ecx`. Note that you need to ensure that the string is null-terminated, too (which is the case here because of little-endianess). Of course you can also reserve space using `subl [size], %esp`. – Niklas B. Aug 31 '12 at 18:30
  • I also finally got around to looking up how I can set breakpoints from within GDB :) – Niklas B. Aug 31 '12 at 18:32
  • Not true that the "string" needs to be null-terminated - this ain't C! – Frank Kotler Aug 31 '12 at 19:15
  • @Frank: Very true, I'm too much used to coding against the libc in assembly :/ – Niklas B. Aug 31 '12 at 19:52