I am trying to write a simple program that prints out a C string without using one of the linux system calls or the standard C library functions. This is for learning purposes only, and I would never do this in production (unless I got really good at it =)).
First my system info:
[mehoggan@fedora sandbox-print_chars]$ uname -a
Linux fedora.laptop 2.6.35.14-106.fc14.i686.PAE #1 SMP Wed Nov 23 13:39:51 UTC 2011 i686 i686 i386 GNU/Linux
[mehoggan@fedora sandbox-print_chars]$ gcc --version
gcc (GCC) 4.5.1 20100924 (Red Hat 4.5.1-4)
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Next the code:
#include <unistd.h>
#include <sys/syscall.h>
void main()
{
char *str = "Hello World";
while(*(str) != '\0') {
//printf("%c", *(str++));
//syscall(__NR_write, 1, *(str++), 1);
__asm__( "movl %0, %%ecx" :"=c" (str));
__asm__( "movl $0X4, %eax" );
__asm__( "movl $0X1, %ebx" );
__asm__( "movl $0X1, %edx" );
__asm__( "int $0X80" );
str++;
}
return;
}
Compiled with the following makefile:
all: sandbox_c
sandbox_c: sandbox.c
gcc -Wall -o sandbox_c ./sandbox.c
gcc -S -Wall -o sandbox_c.asm ./sandbox.c
Things compile just fine, I just cant get the syntax right to get the thing to work. Your corrections are greatly appreciated, but if you could also point me to how you obtained the solution that would be great. I am trying to get better at using the man pages etc.
ADDITION Running the executable through gdb I can see that ecx is not being pointed at the right address:
[mehoggan@fedora sandbox-print_chars]$ gdb ./sandbox_c
GNU gdb (GDB) Fedora (7.2-52.fc14)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/mehoggan/Code/Assembly/sandbox/sandbox-print_chars/sandbox_c...done.
(gdb) break sandbox.c:8
Breakpoint 1 at 0x80483a2: file ./sandbox.c, line 8.
(gdb) run
Starting program: /home/mehoggan/Code/Assembly/sandbox/sandbox-print_chars/sandbox_c
Breakpoint 1, main () at ./sandbox.c:8
8 while(*(str) != '\0') {
Missing separate debuginfos, use: debuginfo-install glibc-2.13-2.i686
(gdb) step
11 __asm__( "movl %0, %%ecx" :"=c" (str));
(gdb) info registers
eax 0x48 72
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x567ff4 5668852
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483a4 0x80483a4 <main+16>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
12 __asm__( "movl $0X4, %eax" );
(gdb) info registers
eax 0x48 72
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x34092fad 873017261
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483ab 0x80483ab <main+23>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
13 __asm__( "movl $0X1, %ebx" );
(gdb) info registers
eax 0x4 4
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x34092fad 873017261
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483b0 0x80483b0 <main+28>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
14 __asm__( "movl $0X1, %edx" );
(gdb) info registers
eax 0x4 4
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x1 1
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483b5 0x80483b5 <main+33>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
15 __asm__( "int $0X80" );
(gdb) info registers
eax 0x4 4
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x1 1
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483ba 0x80483ba <main+38>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) step
16 str++;
(gdb) info registers
eax 0xfffffff2 -14
ecx 0x34092fad 873017261
edx 0x1 1
ebx 0x1 1
esp 0xbffff2a4 0xbffff2a4
ebp 0xbffff2b8 0xbffff2b8
esi 0x0 0
edi 0x0 0
eip 0x80483bc 0x80483bc <main+40>
eflags 0x200206 [ PF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
Try this:
__asm__ volatile ( "movl $0X4, %eax
movl $0X1, %ebx
movl $0X1, %edx
int $0X80"
: /* outputs: */ /* none */
: /* inputs: */ "c" (str)
: /* clobbers: */ "eax", "ebx", "edx");
I've not tested it, but the syntax looks right. You might need to add some more "clobbers" if the syscall overwrites anything else - check the documentation.
Breaking it down:
%0
to %ecx
because the "c"
constraint already did that.str
is an input, but you had it as an output.volatile
tells the compiler not to remove it - it has no output so the compiler might think it can.