views:

201

answers:

2

is it possible to write a single character using a syscall from within an inline assembly block? if so, how? it should look "something" like this:

__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " movl $80, %%ecx \n\t"
                     " movl $0,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );

$80 is 'P' in ascii, but that returns nothing.

any suggestions much appreciated!

+2  A: 

IIRC, two things are wrong in your example. Firstly, you're writing to stdin with mov $0, %ebx Second, write takes a pointer as it's second argument, so to write a single character you need that character stored somewhere in memory, you can't write the value directly to %ecx

ex:
.data
char: .byte 80
.text
mov $char, %ecx

I've only done pure asm in linux, never inline using gcc, you can't drop data into the middle of the assembly, so I'm not sure how you'd get the pointer using inline assembly.

EDIT: I think I just remembered how to do it. you could push 'p' onto the stack and use %esp

pushw $80
movl %%esp, %%ecx
... int $0x80 ...
addl $2, %%esp

cthom06
in C i do "the same" with `char *p = 'P'; write(1, `, so stdout is 1
guest
char *p = 'P' should be char p = 'P' I suppose.
ShinTakezou
`write()` takes `const void *buf` as its second argument
guest
just figured, you are right of course! should be `char p`
guest
thx! i was just wondering how that would work with `push`.. what is the difference in using `push` and `pushb`, tho? and do i have to pop them, when i'm done?
guest
@cthom ... it would be a good idea but 1) pushb does not exist, and it would de-align the stack, which is better dword-aigned (or at least word aligned); in fact instead of my pushl, the asker can put `pushw` and end the code with `add $2, %esp`.
ShinTakezou
@Shin yah, i just noticed that. I don't think unaligning the stack would matter much since you realign right after, fixing it now though.
cthom06
no in fact, but since pushb does not exist you'd stick to subl $1, %esp; movb $80, (%esp); .... addl $1, %esp ; ... which is nice anyway, but one instruction longer
ShinTakezou
+1  A: 

Something like


char p = 'P';

int main()
{
__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " leal p , %%ecx \n\t"
                     " movl $0,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );
}

Add: note that I've used lea to Load the Effective Address of the char into ecx register; for the value of ebx I tried $0 and $1 and it seems to work anyway ...

Avoid the use of external char

int main()
{
__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " subl $4, %%esp \n\t"
                     " movl $80, (%%esp)\n\t"
                     " movl %%esp, %%ecx \n\t"
                     " movl $1,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     " addl $4, %%esp\n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );
}

N.B.: it works because of the endianness of intel processors! :D

ShinTakezou
guest
is there a way, to _not_ declare p within C, but inside the assembly block? when looking at GCCs assembly output, it looks like, this should be possible. i hope this is the relevant part:`movl $80, -8(%ebp)` `movl $1, 8(%esp)` `leal -8(%ebp), %eax` `movl %eax, 4(%esp)` `movl $1, (%esp)` `call write`
guest
of course you can use the stack; the gcc-generated code uses ebp it prepared it before; we can stick to use just esp for the moment; I've modified the answer, see it.
ShinTakezou
awesome!! can it also be done with a `push` and the stackpointer?
guest
you can mke my code better thanks to suggestion of using push (but pushb does not exist and anyway it would "de-align" the stack...): remove subl $4,%esp and instead of `movl $80, (%esp)` put `pushl $80`; the rest is the same.
ShinTakezou
uh seen now your comment; yes as said you can use pushl and avoid decrementing the stack by hand; esp is the stackpointer; to use the base/frame pointer ebp or how you call it, you should preserve the previous value of it in use by C for local variables;... so after all it is not so useful, in this case esp is easier
ShinTakezou
instead of pushl, you can use `pushw $80` and end with `addl $2, %esp`... question of taste, I believe...
ShinTakezou
makes sense to me. so i will stick to your approach (though first i should read up on this topic a bit).. also, you are my personal hero! thx a lot!
guest