News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

gcc inline asm

Started by jcfuller, October 22, 2010, 07:39:38 PM

Previous topic - Next topic

jcfuller

I tried searching elsewhere but I came up empty. Maybe someone familar with gcc/g++ can point me in the right direction.
I am using the MinGwTDM64 gcc compiler from here http://tdm-gcc.tdragon.net/.
It will compile to 32 or 64 bit apps by just using -m32 or -m64. It works fine and I have compiled loads of c++ code to both 32 and 64.

Problem:
I am attempting to use inline intel syntax assembly.

This bit of code compiles and works but only when compiled to a 64bit app.
Any one know how to create a 32bit app?

My OS is Win7 64.



/* compiled with gcc asmtest.c -o asmtest.exe -masm=intel */

/* defaults to 64bit */

#include <stdio.h>
#include <string.h>

char test[] = "James\n";
int len;

int main (void)
{
    printf("this is a sample intel syntaxed and inlined c program\n");
    len = strlen(test);
    printf("%d\n",len);
    asm(".intel_syntax noprefix\n");
    asm("mov eax, offset test\n");
    asm("mov byte ptr[eax],65\n");
    printf(test);
    return 1;
}


Gunther

Hallo James,

I'm not sure if I understand you right. But in a 32 bit application it isn't so easy to fetch parameters by name with the inline assembler (unfortunately it isn't PB). So, try this:


#include <stdio.h>
#include <string.h>

void change(char *p);

int main(int argc, char **argv)
{
  char test[] = "James\n";
  int len;
  char *p = &test[0];
  printf("this is a sample intel syntaxed and inlined c program\n");
  len = strlen(test);
  printf("%d\n",len);
  printf(test);
  change(p);
  printf(test);
  return 0;
}

void change(char *p)
{
  __asm__ __volatile__(
    ".intel_syntax noprefix \n\t"
    "mov        eax,[ebp+8]                     \n\t"
    "mov        byte ptr [eax],65               \n\t"
    ".att_syntax prefix \n\t"
    :
    :"g"(p)
    :"%eax"
    );
}


It works fine with my 32 bit Win XP and leads to the following output:


this is a sample intel syntaxed and inlined c program
6
James
Aames


It's always a good idea to use the extended inline syntax (very powerful) and to encapsulate the assembly language functions in separate modules. I hope that helps a tad.

Gunther
Forgive your enemies, but never forget their names.

jcfuller

Gunther,
  No go with your code.  I get an undefined reference to 'ebp'
This is basically the same error I get with my original code when trying to compile to a 32bit app.
    undefined reference to 'test'.
Your code also gpf's when compiled to a 64bit app.
Your suggestion of separate modules kinda defeats the purpose. If I use a separate module I'd use jwasm.

It is perplexing as compiling my code to a 64bit app works with what seems to be "32bit" assembler coding?

Also I don't want att syntax.

Note: My OS is  Win7 64.

James

MichaelW

James,

FWIW the code you posted compiles OK with the gcc 3.4.5 from a recent MinGW installation and the EXE runs OK under Windows 2000. Can you compile a 32-bit app with the inline assembly in AT&T syntax?
eschew obfuscation

jcfuller

Quote from: MichaelW on October 23, 2010, 10:45:38 AM
James,

FWIW the code you posted compiles OK with the gcc 3.4.5 from a recent MinGW installation and the EXE runs OK under Windows 2000. Can you compile a 32-bit app with the inline assembly in AT&T syntax?

I'm not surprised at that as I expect it might have something to do with a linker directive when compiling to 32bit on a native 64bit OS.
I have no idea how to write at&t syntax nor do I want to :) . The whole premise of this exercise was to use intel syntax .
It may very well be the compiler but they do not have forum.
I thought I would post here first as there are many here who are well versed in a number of different languages.

James



Gunther

James,

the trick is: you can't fetch the parameters with intel syntax. You've to use AT&T syntax for that, so you could write for example:

movl        %0, %eax


Furthermore, the program models of Win 64 bit and Unix 64 bit are very different. Under Unix (Linux, BSD etc.) the parameters are passed via registers, not via stack. From there comes the GPF under 64 bit.

Quote from: jcfuller, October 23, 2010,at 10:58:45 AMIf I use a separate module I'd use jwasm.

Yes, that will work fine for C programs. C++ is another world with name mangling and name decoration and different schemes for different compilers. So the inline assembler is sometimes a better choice, especially for class member functions.

Unfortunately, I haven't a 64 bit Windows running at the moment (only 64 bit Linux). Therefore, I can't test your original code now. Perhaps next week with the help of a friend.
 

Gunther
Forgive your enemies, but never forget their names.

jcfuller

Gunther,
  You are confusing me more than I was :)

MichaelW just stated that my original code will compile and run fine on a Windows 32bit OS using the  MinGw 32bit compiler set.

I am using the 32/64 gcc/g++ from http://tdm-gcc.tdragon.net/  on Win7 64.

Do you have any experience with this compiler and is the reasons for your "need at&t syntax" statement?

As I said I have compiled quite a lot of c++  code to both 32 and 64 bit with just a -m32/-m64 command line switch with this compiler.

James

jcfuller

I only have one 32bit system a VirtualBox XP.
I tried the original code there and it also failed with gcc 4.4.1

So it appears to be latter gcc builds that fail with 32bit?

James



alp

I recall using TDM-GCC for compiling an opensource application, the linker gave me lot of problems, in the end i just have to quit.

MichaelW

James,

Sorry, I was half asleep when I did my tests and it was Gunther's code that I tested, not yours. For your code, as posted, and compiling with:

gcc -pedantic -Os test.c -o test.exe -std=c99 -masm=intel

I get warning: implicit declaration of function 'asm', followed by three undefined reference to 'asm' messages, apparently from the linker.

But if I modify your code to this:

/* compiled with gcc asmtest.c -o asmtest.exe -masm=intel */

/* defaults to 64bit */

#include <stdio.h>
#include <string.h>

char test[] = "James\n";
int len;

int main (void)
{
    printf("this is a sample intel syntaxed and inlined c program\n");
    len = strlen(test);
    printf("%d\n",len);
      __asm__ (
      ".intel_syntax noprefix\n"
      "mov eax, offset _test\n"  /* note leading underscore*/
      "mov byte ptr[eax],65\n"
    );
    printf(test);
    return 1;
}


Then it compiles OK and the EXE runs OK.
eschew obfuscation

Gunther

James,

Quote from: jcfuller, October 23, 2010, at 02:08:55 PMYou are confusing me more than I was :)

That wasn't my plan, sorry.  :( But joke apart: There are several things to remember. First, the ABI (Application Binary Interface) under 32 bit and 64 bit is very different. Furthermore, the Win 64 ABI and the Unix 64 ABI are also different worlds. You may wish to check the differences, for example here: http://www.x86-64.org/documentation.html

I have a serious doubt - mildly spoken - that one compiler can solve both ABI requirements of 32 bit and 64 bit Unix. Anyway, I've ported your code to 64 bit Linux:


/*
build the application under 64 bit Linux with:
gcc -o string string.c
fire it up at the command line:
./string
compiled with gcc 4.4.5
*/

#include <stdio.h>
#include <string.h>

void change(char *p);

int main(int argc, char **argv)
{
  char test[] = "James\n";
  int len;
  char *p = &test[0];
  printf("this is a sample intel syntaxed and inlined c program\n");
  len = strlen(test);
  printf("%d\n",len);
  printf("%s",test);
  change(p);
  printf("%s",test);
  return 0;
}

/*
change
Purpose: Change a character pointed by register rdi.
Input: rdi -> character array
Output: character changed
*/
void change(char *p)
{
  __asm__ __volatile__(
    ".intel_syntax noprefix \n\t"
    "mov byte ptr [rdi],65 \n\t"
    ".att_syntax prefix \n\t"
    :
    :"g"(p)
    :"%rax"
    );
}


You can see the differences to the 32 bit version I've posted above. It works well and gives the same output.

Quote from: alp, October 23, 2010, at 06:24:09 PMI recall using TDM-GCC for compiling an opensource application, the linker gave me lot of problems, in the end i just have to quit.

May be that this is one source of your trouble. I would use the original MinGW for windows from SourceForge (available as 32 bit or 64 bit version). You can install both at your machine.

Gunther
Forgive your enemies, but never forget their names.

jcfuller

Thanks Gunther but Windows is my main concern at present, and it appears (right or wrong) the same code except for the leading underscore to(_)test compiles and works with both 32 and 64 bit?
Need to do some more testing but at least I can compile to 32bit now. Thank you Michael. Any idea why 64 does not need the underscore and 32bit does??

Just to note I compiled with:   gcc asmtest.c -o asmtest.exe -masm=intel -m32
gcc version (tdm64-1) 4.5.1
compiled on Win7 64

James

MichaelW

Quote from: jcfuller on October 23, 2010, 07:54:04 PM
Any idea why 64 does not need the underscore and 32bit does??

I can guess that the compiler is simply copying the inline assembly code to its output. If I leave off the leading underscore and compile with:

gcc -pedantic -Os testok.c -S -o testok.asm -std=c99 -masm=intel

Then I get this:

.file "testok.c"
.intel_syntax
.globl _test
.data
_test:
.ascii "James\12\0"
.text
.def _printf; .scl 3; .type 32; .endef
_printf:
push ebp
mov ebp, esp
lea eax, [ebp+12]
push eax
push DWORD PTR [ebp+8]
call ___mingw_vprintf
leave
ret
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "this is a sample intel syntaxed and inlined c program\12\0"
LC1:
.ascii "%d\12\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
push ebp
mov ebp, esp
push edi
mov edi, OFFSET FLAT:_test
call ___main
push OFFSET FLAT:LC0
call _printf
cld
xor eax, eax
or ecx, -1
repne scasb
not ecx
dec ecx
push ecx
push OFFSET FLAT:LC1
mov DWORD PTR _len, ecx
call _printf
/APP
.intel_syntax noprefix
mov eax, offset test
mov byte ptr[eax],65

/NO_APP
push OFFSET FLAT:_test
call _printf
mov edi, DWORD PTR [ebp-4]
mov eax, 1
leave
ret
.comm _len, 16 # 4
.def ___mingw_vprintf; .scl 2; .type 32; .endef

eschew obfuscation

jcfuller

Ok I got it.
I want just 32bit so this is fine. I was just confused (and still am) why it compiled to 64bit with what I considered 32bit asm code?

Anyway the only thing I don't understand is the local variable alen at ebp-12. My research said locals begin at ebp-4. I just tried 8 and then 12 on a whim with 12 working??

Again thanks Michael and Gunther.



/* compiled with g++ asmtest12.cpp -o asmtest12.exe -Wno-write-strings  -mconsole -masm=intel -m32*/

#include <stdio.h>
#include <string.h>

void edmUCASE(char* a)
{
int alen = strlen(a);
__asm__(
  ".intel_syntax noprefix\n"
  "mov ecx,[ebp-12]\n"
  "mov eax,[ebp+8]\n"
  "BgnUpLoop:\n"
  "mov dl,[eax]\n"
  "cmp dl,97\n"
  "jb NoDnChar\n"
  "cmp dl,123\n"
  "jb MakeUpper\n"
  "cmp dl,224\n"
  "jb NoDnChar\n"
  "cmp dl,247\n"
  "jb MakeUpper\n"
  "je NoDnChar\n"
  "cmp dl,255\n"
  "jb MakeUpper\n"
  "jmp NoDnChar\n"
  "MakeUpper:\n"
  "sub dl,32\n"
  "mov [eax],dl\n"
  "NoDnChar:\n"
  "inc eax\n"
  "dec ecx\n"
  "jnz BgnUpLoop\n"
);
}
int main (int argc, char** argv)
{
    static char S[]="James";
    printf("%s\n",S);
    edmUCASE(S);
    printf("%s\n",S);
    return 0;
}