Page 1 of 2

GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 11:27 am
by Ch4ozz
So this is like the 500th time GCC fucks with my inline asm and I have no idea why.
This is my small little function in C:

Code: Select all

int i;
for(i = 0; i < vfs_drive_cnt; i++)
{
	char szPath[64];
	sprintf(szPath, "%c:\\DATA\\APPS\\CMD.BIN", vfs_drive[i].letter);

	asm volatile("push %eax; push %ebx");
	asm volatile("int $0x30" : : "a"(14), "b"(szPath));
	asm volatile("pop %ebx; pop %eax");
}
But GCC ends up with this:

Code: Select all

.text:020223B4                 push    eax
.text:020223B5                 push    ebx
.text:020223B6                 mov     eax, [ebp+var_268]
.text:020223BC                 int     30h             ; (NOT A VECTOR!) FAR JMP instruction for CP/M-style calls
.text:020223BE                 pop     ebx
.text:020223BF                 pop     eax
Is there something I forgot?
Im compiling on O3

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 11:35 am
by Octacone
Try:

Code: Select all

__asm__ __volatile__

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 11:36 am
by Ch4ozz
octacone wrote:Try:

Code: Select all

__asm__ __volatile__
I have a define which replaces asm and volatile with those.
It makes no difference sadly.

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 11:37 am
by Octacone
Ch4ozz wrote:
octacone wrote:Try:

Code: Select all

__asm__ __volatile__
I have a define which replaces asm and volatile with those.
It makes no difference sadly.
:| Could it be your linker?

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 11:40 am
by Ch4ozz
octacone wrote::| Could it be your linker?
This has nothing todo with the linker.
The object file looks the exact same

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 11:50 am
by Octocontrabass
Please read the wiki page on inline assembly.

Each block of inline assembly is an independent piece, and GCC has no idea what they do. It will freely reorder them (or remove them!) if it thinks it's safe to do so. If you want some instructions to be a single block of code, you must put them in a single asm statement. Since GCC can't parse inline assembly, you must tell it about anything you clobber that GCC might expect to use later (e.g. registers, memory, condition codes).

Edit:

Oh, and one more thing: you don't need to push registers onto the stack to save them. If your asm statement is correct, GCC will do that for you. (It's also clever enough to avoid wasting time saving things it won't use again.)

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 12:02 pm
by Rusky
Ch4ozz wrote:

Code: Select all

	asm volatile("push %eax; push %ebx");
	asm volatile("int $0x30" : : "a"(14), "b"(szPath));
	asm volatile("pop %ebx; pop %eax");
There's no need to push/pop those registers yourself, since you're already telling GCC that you're using them on the second line. And in the general case, there's still no need to push/pop anything yourself- just mark anything you change as clobbered and let the compiler's register allocator handle it.

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 12:18 pm
by Ch4ozz
Well the first thing I tried was this:

Code: Select all

asm volatile("int $0x30" :: "a"(14), "b"(szPath));
I didnt directly look at the produced asm thats why I added push and pops.

Anyways, thanks for the replies, I understood that I have to inform the compiler about changes of the registers using clobbers.
I never used much GCC inline asm because I dont like its syntax (intel syntax is better imo)

So this is what I tried:

Code: Select all

asm volatile("int $0x30" :: "a"(14), "b"(szPath) : "eax", "ebx");
But it doesnt compile and I really dont see why.
I already got it to work by putting everything into one asm statement:

Code: Select all

asm volatile(
			"push %%eax;"
			"push %%ebx;"
			"int $0x30;"
			"pop %%ebx;"
			"pop %%eax;" 
				: : 
				"a" (14),
				"b" (szPath)
			);
But I try to learn how to use the clobber list properly.

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 12:48 pm
by Rusky
You're already telling GCC which registers you're using, so there's no need for you to use the clobber list or push/pop in this case. The clobber list is only necessary when e.g. the instruction you use implicitly modifies some registers that aren't marked as outputs.

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 1:03 pm
by Ch4ozz
Rusky wrote:You're already telling GCC which registers you're using, so there's no need for you to use the clobber list or push/pop in this case. The clobber list is only necessary when e.g. the instruction you use implicitly modifies some registers that aren't marked as outputs.
Ahhh okay understood this.
Anyways, why this code is still having the wrong result then?

Code: Select all

asm volatile("int $0x30" :: "a"(14), "b"(szPath));

Code: Select all

.text:020223AF                 call    sprintf
.text:020223B4                 mov     eax, [ebp+var_268]
.text:020223BA                 int     30h             ; (NOT A VECTOR!) FAR JMP instruction for CP/M-style calls

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 1:29 pm
by Rusky
Without more context it's impossible to say- the correct values should be in eax and ebx at the point of the `int` instruction- might be good to confirm that in a debugger, though. It's also possible this part is working fine but you have an unrelated issue somewhere else.

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 1:33 pm
by Ch4ozz
Rusky wrote:Without more context it's impossible to say- the correct values should be in eax and ebx at the point of the `int` instruction- might be good to confirm that in a debugger, though. It's also possible this part is working fine but you have an unrelated issue somewhere else.
Well if you look at the IDA output I posted above, you will see that it moves the string into eax and nothing into ebx.
This is indeed wrong but I dont see a single reason for this.
It works well with -O0

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 1:42 pm
by mikegonta
Ch4ozz wrote:Well the first thing I tried was this:

Code: Select all

asm volatile("int $0x30" :: "a"(14), "b"(szPath));
Works fine for me.
Ch4ozz wrote:I never used much GCC inline asm because I dont like its syntax (intel syntax is better imo)
Use the GCC command-line option -masm=intel for intel syntax.
Ch4ozz wrote:So this is what I tried:

Code: Select all

asm volatile("int $0x30" :: "a"(14), "b"(szPath) : "eax", "ebx");
But it doesnt compile and I really dont see why.

Code: Select all

error: 'asm' operand has impossible constraints
GCC doesn't like to be told what it already knows.

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 2:03 pm
by tsdnz
Ch4ozz wrote:So this is like the 500th time GCC xxxx with my inline asm and I have no idea why.
This is my small little function in C:

Code: Select all

int i;
for(i = 0; i < vfs_drive_cnt; i++)
{
	char szPath[64];
	sprintf(szPath, "%c:\\DATA\\APPS\\CMD.BIN", vfs_drive[i].letter);

	asm volatile("push %eax; push %ebx");
	asm volatile("int $0x30" : : "a"(14), "b"(szPath));
	asm volatile("pop %ebx; pop %eax");
}
But GCC ends up with this:

Code: Select all

.text:020223B4                 push    eax
.text:020223B5                 push    ebx
.text:020223B6                 mov     eax, [ebp+var_268]
.text:020223BC                 int     30h             ; (NOT A VECTOR!) FAR JMP instruction for CP/M-style calls
.text:020223BE                 pop     ebx
.text:020223BF                 pop     eax
Is there something I forgot?
Im compiling on O3
This first example should show you how to set and get.

Code: Select all

	QWORD setAndGetRAX = 14;
	QWORD setAndGetRBX = 0x12345678;
	BYTE  N = 0x30;
	asm volatile("int %2;" : "+a"(setAndGetRAX), "+b"(setAndGetRBX) : "N"((N)) : "cc", "memory");
	if (setAndGetRAX == setAndGetRBX) Util.Loop();

Code: Select all

  302011:	b8 0e 00 00 00       	mov    eax,0xe
  302016:	bb 78 56 34 12       	mov    ebx,0x12345678
  30201b:	cd 30                	int    0x30
  30201d:	48 39 d8             	cmp    rax,rbx
  302020:	74 5c                	je     30207e <ss+0x34>
.....
  30207e:	eb fe                	jmp    30207e <ss+0x34>
This will set.

Code: Select all

	QWORD setRAX = 14;
	QWORD setRBX = 0x12345678;
	BYTE  N = 0x30;
	asm volatile("int %2;" : : "a"(setRAX), "b"(setRBX), "N"((N)) : "cc", "memory");

Code: Select all

  302011:	b8 0e 00 00 00       	mov    eax,0xe
  302016:	bb 78 56 34 12       	mov    ebx,0x12345678
  30201b:	cd 30                	int    0x30

Re: GCC "optimizing" wrong (again)

Posted: Fri Aug 12, 2016 2:15 pm
by tsdnz
Ch4ozz wrote:But GCC ends up with this:

Code: Select all

.text:020223B4                 push    eax
.text:020223B5                 push    ebx
.text:020223B6                 mov     eax, [ebp+var_268]
.text:020223BC                 int     30h             ; (NOT A VECTOR!) FAR JMP instruction for CP/M-style calls
.text:020223BE                 pop     ebx
.text:020223BF                 pop     eax
Is there something I forgot?
Im compiling on O3
The reason ebx is not set in your snippet is it must have been set when sfprint was called.