Page 1 of 1

Garbage inline assembly?

Posted: Sun Nov 22, 2009 6:57 pm
by AUsername
There is a reason why I use VC++ over GCC. Because AT&T took a perfectly good language, assembly, and destroyed the syntax. And then GCC decided to take the butchered syntax of AT&T's assembly and make it even worse.

I seriously need some help cause this code works in VC++ but not in GCC:

Firstly, I'm calling a system from a program in kernel space, so here's what I did in GCC:

main.c:

Code: Select all

int main(){
	static char* str = "Hello World!";
	__asm__("mov $1, %eax");
	__asm__("mov %0, %%esi \n\t int $0x30" :: "r" (str) );
        __asm__("cli");
        __asm__("hlt");

	return 0;
}
Running the code the switchboard (API) reports that EAX is a garbage value, ESI being the same garbage value.

I'm honestly stumped because it destroys all the volatile registers.

It may possibly be my linker.ld:

Code: Select all

ENTRY(entrypoint)

SECTIONS{
    . = 0x00100000;

    .text :{
        *(.text)
    }

    .rodata ALIGN (0x1000) : {
        *(.rodata)
    }

    .data ALIGN (0x1000) : {
        *(.data)
    }

    .bss : {
        sbss = .;
        *(COMMON)
        *(.bss)
        ebss = .;
    }
}
or my entry.s:

Code: Select all

global entrypoint
extern main

section .text
align 4

entrypoint:
	call	main
	ret
I honestly don't see the problem here.

Note: I tested the assembly code in my kernel, compiled in VC++ and it works perfectly, just to rule out any external variables.

Full source: http://firefly-os.com/downloads/tmp/programs.zip
ld-elf: http://firefly-os.com/downloads/tmp/ld-elf.exe

EDIT: Updated the code and now it halts, no idea why it was ignoring me previously.

Any help as to what's going wrong would be greatly appreciated.
Thanks. ^-^

Re: Garbage inline assembly?

Posted: Sun Nov 22, 2009 7:41 pm
by pcmattman
You're missing a volatile keyword, so GCC is totally free to ignore any of the assembly you're adding in if it deems it pointless (which it is). You also need to try and combine your assembly blocks as much as possible, as you have zero control over what GCC adds between them (and you could easily lose important values in registers because of that).

Try something like this:

Code: Select all

asm volatile ("mov $1, %eax; \
                   mov %0, %%esi; \
                   int $0x30" :: "r" (str));
asm volatile ("cli;hlt");
May not work directly, but it should clear things up a bit.

Re: Garbage inline assembly?

Posted: Sun Nov 22, 2009 7:47 pm
by AUsername
Thanks Matt, that helped out a little, how it sets both ESI and EAX to 0x1.

Edit:

Found out why:

Code: Select all

mov $1, %eax;
mov %eax, %esi;
int $0x30
Apparently, GCC doesn't know how to compi---
I mean, it tries to use EAX to move str into ESI, but never sets EAX to str...

I can set ESI first but it doesn't fix it it just takes the value from some stack code previous to it.

How does:

Code: Select all

	asm volatile ("mov $1, %%eax; \
				   mov %0, %%esi; \
				   int $0x30" :: "r" (str));

equal the code above...

Re: Garbage inline assembly?

Posted: Sun Nov 22, 2009 9:34 pm
by gravaera
Salutations;

Please try reading the GAS manuals, since they give so much insight into everything. You may want to change those 'mov's into 'movl's. In fact I'm surprised that code compiles at all. I've never been able to get code to compile on GAS without the proper suffixes.

The general format for GCC inline is:

Code: Select all

asm volatile ("
   instruction \n\t
   instruction %0, %%reg \n\t
   instruction %%reg, %%reg"
   : "destination-constraint" (destination-operand)
   : "source-constraint" (source-operand)
   : clobbered-register-list
   );
--Good luck
gravaera

Re: Garbage inline assembly?

Posted: Sun Nov 22, 2009 9:40 pm
by pcmattman
AUsername wrote:How does:

Code: Select all

	asm volatile ("mov $1, %%eax; \
				   mov %0, %%esi; \
				   int $0x30" :: "r" (str));

equal the code above...
GCC has no idea about the code within an ASM block. It's basically inserted verbatim into the generated assembly code that's given to AS.

You probably want to set EAX and ESI as clobbered registers. Clobbers aside, the best solution would be something like this:

Code: Select all

	asm volatile ("mov $1, %%eax; \
				   int $0x30" :: "S" (str)); // add your clobbered registers

What that does is pass "str" in ESI, so you don't need to do it yourself.

EDIT: The "r" constraint basically lets GCC allocate a register as it sees fit for the inline assembly block. However, it does that without knowledge of the assembly that's in the block, so it won't automatically stop using registers which it shouldn't. The "S" constraint tells GCC to generate assembly to shove "str" into ESI before the block begins, so it's already all set up and ready to go and you don't need to write an instruction for it. Just a bit of background in case the above doesn't explain that.

Re: Garbage inline assembly?

Posted: Mon Nov 23, 2009 1:53 am
by Solar
AUsername wrote:AT&T took a perfectly good language, assembly, and destroyed the syntax.
If you want that to mean that AT&T took the Intel syntax and butchered it, you are mistaken. AT&T syntax predates the Intel 8086 by a couple of years (unless I am severly mistaken).

And then there are people who actually prefer the AT&T syntax exactly because it's movl %src, %dest instead of mov dest, src...

And to make this not purely flame-bait: You might want to try .intel_syntax. Perusing the GAS manual is also a good idea.

Re: Garbage inline assembly?

Posted: Mon Nov 23, 2009 4:20 am
by qw
AUsername,
Don't blame GCC for your mistakes. You're the one feeding four separate inline asm instructions. You're the one telling GCC to load the address into a register before loading it into ESI. You're the one not telling the compiler that you're clobbering EAX and ESI. Read the manual.

Re: Garbage inline assembly?

Posted: Mon Nov 23, 2009 9:25 am
by fronty
gravaera wrote:You may want to change those 'mov's into 'movl's. In fact I'm surprised that code compiles at all. I've never been able to get code to compile on GAS without the proper suffixes.
IIf you don't provide suffixes, GAS guesses operands' sizes. You can quite safely omit suffixes when copying from gpr to gpr, but in my opinion the right thing to do is be consistent in source code and use suffixes everywhere. It makes your intensions clearer to someone reading your code.