Assembly in C - Printing specific word backwards - c

I have a huge problem with printing the specific word backwards. I'm trying to find words with '*' at the beggining and print them backwards, the rest should be printed normally.
For example:
Input: aaa1 ab0 1kk *ddd *lel 2cccc2 c1
Output aaa1 ab0 1kk ddd* lel* 2cccc2 c1
All I have is finding the words, finding the ones with '' and printing normally the words without ''.
Please help me and thank you in advance for your attention to this matter...
Have to write it in C language and here's my code
int main() {
char *x = "aaa1 ab0 1kk *ddd *lel
2cccc2 c1";
char bufor[100];
asm volatile (
".intel_syntax noprefix;"
"mov eax, %0;"
"push eax;"
"mov eax, %1;"
"push eax;"
"call zadanie1;"
"jmp wyjscie;"
"zadanie1:"
//
// FUNCTION START
//
"pushad;"
"mov esi, [esp+40];"
"mov edx, [esp+36];"
"push edx;"
"xor ecx, ecx;"
// MAIN LOOP - WORDS SEARCHING
"zad_loop:"
"mov edx, [esp];"
"lodsb;"
"test al, al;"
"jz zad_loop_end;"
"cmp al, 0x20;"
"jz zad_loop_end;"
"mov [edx+ecx], al;"
"inc ecx;"
"jmp zad_loop;"
// MAIN LOOP END
"zad_loop_end:"
"mov [edx+ecx], ch;"
"push eax;"
"push ecx;"
"test ecx, ecx;"
"jz not_print;"
// IS THE FIRST CHAR '*'
"lea eax, [edx];"
"mov al, [eax];"
"cmp al, '*';"
"jz backwards;"
"test al, al;"
"jz not_print;"
// PRINTING THE WORD WITHOUT '*'
"mov edx, [esp];"
"mov ecx, [esp+8];"
"mov ebx, 1;"
"push eax;"
"mov eax, 4;"
"int 0x80;"
"push 0x20;"
"call print_char;"
"pop eax;"
// PRINTING THE WORD WITH '*' - BACKWARDS
"backwards:"
// SKIP PRINTING
"not_print:"
"pop ecx;"
"pop eax;"
"xor ecx, ecx;"
"test al, al;"
"jnz zad_loop;"
// FUNCTION END
"pop edx;"
"push 0x0A;"
"call print_char;"
"popad;"
"ret 8;"
// CHAR OUTPUT
"print_char:"
"pushad;"
"mov edx, 1;"
"lea ecx, [esp+36];"
"mov ebx, 1;"
"mov eax, 4;"
"int 0x80;"
"popad;"
"ret 4;"
"wyjscie:"
".att_syntax prefix;"
:
: "r" (x), "r" (bufor)
: "eax"
);
return 0;
}

Designate a register to be a counter (pick any one you aren't using for other stuff) and set its value to 0.
When you hit a * character, push characters onto the stack until it finds a blank, incrementing the counter with each push.
When a blank is found, pop characters off the stack, decrementing the counter and printing the character each time, until the counter is 0.

I don't know your compiler, but I think your compiler would insert the code that you wrote as text in variables instead of compiling the instructions, because a text that begins with a " will be interpreted as text. Drop these chars.

Related

Get argument from command line in inline assembly

I have to count the number of words in a string that you get as an argument from the command line.
First I made this program:
#include <stdio.h>
#include <string.h>
int main( int argc, char *argv[] ){
char* s;
if(argc==1)
{
s="";
} else {
s = argv[1];
}
//char* s = " aqr b qabxx xryc pqr"; example
int x;
asm volatile(
".intel_syntax noprefix;"
"mov eax,%1;"
"xor edx,edx;"
"jmp petla;"
"petla0:"
"inc eax;"
"petla:"
"cmp [eax],byte ptr 0;"
"jz wyjscie;"
"cmp [eax],byte ptr 32;"
"jz petla0;"
"inc edx;"
"petla1:"
"inc eax;"
"cmp [eax],byte ptr 0;"
"jz wyjscie;"
"cmp [eax],byte ptr 32;"
"jz petla;"
"jmp petla1;"
"wyjscie:"
"mov %0,edx;"
".att_syntax prefix;"
: "=r" (x)
: "r" (s)
: "eax","edx"
);
printf("%hd\n",x);
return 0;
}
and it works fine; I get 5 as answer for "aqr b qabxx xryc pqr". But I need my program written only using assembly code. Something like this:
.intel_syntax noprefix
.globl main
.text
main:
mov ecx,?
?<- here is the issue: I don't know how to get an argument from the command line and access it as a char *.
xor edx,edx
jmp petla
petla0:
inc ecx
petla:
cmp byte ptr [ecx],0
jz wyjscie
cmp byte ptr [ecx],32
jz petla0
inc edx
petla1:
inc ecx
cmp byte ptr [ecx],0
jz wyjscie
cmp byte ptr [ecx], 32
jz petla
jmp petla1
wyjscie:
push edx
push offset msg
call printf
add esp, 8
mov edx,0
ret
.data
msg: .ascii "number of words=%d\n"
So first, let's look at your "working" code. While it works, there are a few "teachable" items here.
First of all, please get in the habit of using comments in your code. I realize English is not your first language so I probably couldn't read your comments, but still, you should have them.
Second, stop using ; to terminate your asm instructions. Yes, it looks a little clunkier to use \n\t, but when you use gcc's -S to output the assembler (a great way to see what's really going on), your code will be a mess without \n\t.
So far, that gets us:
asm volatile(
".intel_syntax noprefix\n\t"
// %1 is read-only, so use eax as temp
"mov eax,%1\n\t"
// # of words found
"xor edx,edx\n\t"
"jmp petla\n"
// Skip over spaces
"petla0:\n\t"
"inc eax\n"
"petla:\n\t"
"cmp [eax],byte ptr 0\n\t"
"jz wyjscie\n\t" // End of string
"cmp [eax],byte ptr 32\n\t"
"jz petla0\n\t" // Another space
// Starting new word
"inc edx\n"
// Walk the rest of the current word
"petla1:\n\t"
"inc eax\n\t"
"cmp [eax],byte ptr 0\n\t"
"jz wyjscie\n\t" // End of string
"cmp [eax],byte ptr 32\n\t"
"jz petla\n\t" // End of word
"jmp petla1\n" // Not end of word
"wyjscie:\n\t"
"mov %0,edx\n\t"
".att_syntax prefix"
: "=r" (x)
: "r" (s)
: "eax","edx"
);
Third, you need to understand that when using extended asm, %0 is just a way to refer to whatever is being passed in as the first argument. In this case, you specify that it must be a register ("=r"). So the value is already a register. Instead of using both edx and %0, you can store the count directly in %0.
Fourth, the purpose of byte ptr is so the assembler knows whether [eax] means: The byte at [eax], the word as [eax], the dword at [eax], etc. Such being the case, it is more commonly placed on the other side of a cmp instruction:
asm volatile(
".intel_syntax noprefix\n\t"
// %1 is read-only, so use eax as temp
"mov eax,%1\n\t"
// # of words found
"xor %0,%0\n\t"
"jmp petla\n"
// Skip over spaces
"petla0:\n\t"
"inc eax\n"
"petla:\n\t"
"cmp byte ptr [eax], 0\n\t"
"jz wyjscie\n\t" // End of string
"cmp byte ptr [eax], ' '\n\t"
"jz petla0\n\t" // Another space
// Starting new word
"inc %0\n"
// Walk the rest of the current word
"petla1:\n\t"
"inc eax\n\t"
"cmp byte ptr [eax], 0\n\t"
"jz wyjscie\n\t" // End of string
"cmp byte ptr [eax], ' '\n\t"
"jz petla\n\t" // End of word
"jmp petla1\n" // Not end of word
"wyjscie:\n\t"
".att_syntax prefix"
: "=r" (x)
: "r" (s)
: "eax","edx"
);
What's next? Oh yeah. When you use jz or jnz, if it doesn't jump, the code falls thru to the next instruction. This means that this:
"cmp byte ptr [eax], 0\n\t"
"jz wyjscie\n\t" // End of string
"cmp byte ptr [eax], ' '\n\t"
"jz petla\n\t" // End of word
"jmp petla1\n" // Not end of word
"wyjscie:\n\t"
Can be done like this:
"cmp byte ptr [eax], 0\n\t"
"jz petla\n\t" // End of word
"cmp byte ptr [eax], ' '\n\t"
"jnz petla1\n\t" // Not end of string
"wyjscie:\n\t"
As a general rule, I avoid doing memory reads multiple times. So where you do:
"cmp byte ptr [eax], 0\n\t"
"cmp byte ptr [eax], ' '\n\t"
I would do:
"mov dl, [eax]\n\t"
"cmp dl, 0\n\t"
"cmp dl, ' '\n\t"
This also lets us get rid of the byte ptr. dl can only hold a byte, so that must be what we are reading.
Another subtle point: In your original code, when you are walking the letters, if you encounter a space, you jump back to petla, where you check again to see if it is a space instead of to petla0 to read the next byte.
And 2 other nits: When comparing something with zero, I use test instead of cmp (generates slightly better code). And while it does exactly the same thing, when I compare 2 values (cmp edx, ' '), I find it easier to think in terms of "Are these things 'equal'" rather than "Is the difference between them zero?" As a result, I would use je instead of jz.
Putting all this together gives me:
asm (
".intel_syntax noprefix\n\t"
// %1 is read-only, so use eax as temp
"mov eax, %1\n\t"
// # of words found
"xor %0,%0\n"
// Skip over spaces
"petla0:\n\t"
"mov dl, [eax]\n\t"
"inc eax\n\t"
"test dl, dl\n\t"
"jz wyjscie\n\t" // End of string
"cmp dl, ' '\n\t"
"je petla0\n\t" // Another space
// Starting new word
"inc %0\n"
// Walk the rest of the current word
"petla1:\n\t"
"mov dl, [eax]\n\t"
"inc eax\n\t"
"cmp dl, ' '\n\t"
"je petla0\n\t" // end of word
"test dl, dl\n\t"
"jnz petla1\n" // not end of string
"wyjscie:\n"
".att_syntax prefix;"
: "=r" (x)
: "r" (s)
: "eax", "edx", "cc", "memory"
);
I also removed the volatile. Since you are using the output (by printing x), this is not required.
I will let you roll any of this that you want to keep into your pure asm by yourself.
As for why your pure asm doesn't work, I'm not on linux, so I can't run this. However, I don't see anything actually wrong with your counting code. You might look at this for accessing the command line arguments, but what you are doing should not give you 1.
How are you specifying your command line? I suspect you are not using the " marks around your string: a.out " aqr b qabxx xryc pqr". This would cause each word to be treated as a separate (null terminated) argument.
Edit 1: After some more reading, it looks like the pointer to argv[1] really should be at [esp + 8]. At least on linux. You aren't on Windows, right? Pretty sure it uses a different scheme.
You can try this to make sure your asm is working correctly, but I'm pretty sure that isn't your problem.
lea ecx, str
// Down by .data add:
str: .ascii " asdf adfs asd f adsf "
You can try using the msg format string you have to print argc. If you are passing the arguments correctly, this should be 2.
Change your msg to use %s, and print out the value from argv[0] (aka [esp+4]). This should be the program name.
Using that %s, you can print out argv[1].

How to change value under memory address in C inline assembly (GCC)

In one of the exercises in my assembler course we have to create a program that will change all uppercase letters in char* to lowercase.
char *a = "AAA BB CCC";
char *b;
asm(
".intel_syntax noprefix;"
"xor ecx, ecx;"
"xor eax, eax;"
"lea eax, [%[a]];" // getting address of the first char into eax
"loop:"
"inc ecx;" // loop variable
"cmp ecx, 10;" // 10 cycles for very character in *a
"jne lowercase;"
"jmp end;"
"lowercase:"
"mov bl, [eax];" // copy value stored under eax address to bl
"add bl, 32;" // make it lowercase in ASCII
"mov [eax], bl;" // copy it back to address stored in eax
"inc eax;" // move pointer to the next char
"jmp loop;"
"end:"
"lea %[b], [eax];"
".att_syntax prefix;"
: [b] "=r" (b)
: [a] "r" (a)
: "eax", "ebx", "ecx"
);
My idea was to get address of the first char, increase it by 32 (making it lowercase in ASCII), save it on the same address, than move pointer to the next char and so on. Getting first char and adding 32 to it works fine, its this line that throws "Segmentation fault":
"mov [eax], bl;"
From what I understand it should change value under address held in eax to value of bl. I feel like I'm missing something obvious, but I'm pretty new to this and everything I found so far on the net leads me to believe that this is how I should do it.

Segmentation fault: 11 Assembly OSX

Hi I'm still new to the Assembly language using gcc compiler, right now I'm working on functions.
My program asks the user for 4 int values, store those values in register eax, ebx, ecx and edx, then calls a function to divide (ebx/eax). I store the value of "d" after the division because as I understand idiv uses edx to store the residue. It then subtracts (eax-ecx) and multiply (eax*edx), then returns the value inside of register eax. For some reason I get a segmentation fault: 11.
Here is my code:
#include <stdio.h>
int a, b, c, d;
int main (void)
{
printf("Dame a: ");
scanf("%d", &a);
printf("Dame b: ");
scanf("%d", &b);
printf("Dame c: ");
scanf("%d", &c);
printf("Dame d: ");
scanf("%d", &d);
__asm( ".intel_syntax noprefix;"
"xor eax, eax;"
"mov eax, dword ptr [_a];"
"xor ebx, ebx;"
"mov ebx, dword ptr [_b];"
"xor ecx, ecx;"
"mov ecx, dword ptr [_c];"
"Call fun1;"
"mov dword ptr [_a], eax;"
"fun1: xor edx, edx;"
"idiv ebx;"
"sub eax, ecx;"
"mov edx, dword ptr [_d];"
"imul eax, edx;"
"ret;"
".att_syntax");
printf("%d\n", a);
}
Is it something to do with some pointer error?
Aside from the other errors pointed out in comments, you have a significant issue here:
"mov ecx, dword ptr [_c];"
"Call fun1;"
"mov dword ptr [_a], eax;"
"fun1: xor edx, edx;"
"idiv ebx;"
"sub eax, ecx;"
"mov edx, dword ptr [_d];"
"imul eax, edx;"
"ret;"
Consider the program flow. Your C code falls into this assembly code. The assembly code calls an internal function of its own (not a problem), which then returns to the instruction before the call... Still no problem. A value is moved into EAX... and you then fall through your function to a return. This is horribly bad.
By falling through to that ret you are bypassing the entire C function epilog. This means that the stack is not properly cleaned up, nor is the stack from restored. This will almost certainly lead to a crash.

Assembly , no such instruction popl?

I have a code in C where the main tak is written in Assembly. The idea of the programm is to for example when x = abc def ,and y = a it deletes the word where at least one letter is the same and writes words without the same letters so it would write def. I have wrotten a code, but it gives error like :
prog.c:10: Error: no such instruction: `addl $112,%esp'
prog.c:12: Error: no such instruction: `xorl %eax,%eax'
prog.c:13: Error: no such instruction: `popl %ebx'
prog.c:16: Error: no such instruction: `popl %esi'
Here is the code :
#include <stdio.h>
#include <string.h>
int main(){
char *x = "asbc4a2bab ";
char *y = "ab";
char bufor[100];
asm volatile (
".intel_syntax noprefix;"
"mov ecx,%0;"
"push ecx;" //wrzuca na stos
"mov ecx,%1;"
"mov eax,%2;"
"call zadanie1;"
"jmp wyjscie;"
"zadanie1:"
"push ebp;" //wrzucamy ebp na stos
"push eax;"
"push ecx;" //ecx zliczanie
"push edi;" //edi destination
"mov ebp,esp;" //do ebp adres stosu
"mov esi,[ebp+20];" //esi bezposrednio do x
"mov edi,[ebp+4];" //edi adres y
"mov ebx,[ebp+8];"//ebx bufor
"mov eax,0;"//eax to false
"push eax;"
"push esi;"
"push eax;"
"etykieta_x:"
"mov eax,[esp+8];"
"cmp eax,0;"
"je etykieta_y;"
"mov [esp+4],esi;"
"mov eax,0;"
"mov [esp+8],eax;"
//"mov [esp+4],esi;"
"etykieta_y:"
"mov eax,[edi];"
"cmp eax,'\0';" //porownoje eax z koncem
"je koniec_etykiety_x;"
"add edi,1;"//zwiekszamy petle
"cmp eax,[esi];"//porownoje y i x
"jne etykieta_y;"//wrocimy do etykiety y jesli nie sa rowne
"ustaw_flage:"
"pop eax;"
"mov eax,1;" //ustawia flage
"push eax;"
"koniec_etykiety_x:"
"pop eax;"
"cmp eax,1;"
"jne iteruj_dalej;"
"mov eax,0;"
"push eax;"
"iteruj_po_znakach:"
"add esi,1;"
"mov eax,[esi];"
"cmp eax,'\0';"
"je koniec;"
"cmp eax,' ';"
"je spacja_wykryta;"
"jmp etykieta_x;"
"spacja_wykryta:"
"mov eax,1;"
"mov [esp+8],eax;"
"jmp iteruj_po_znakach;"
"iteruj_dalej:"
"mov eax,0;"
"push eax;"
"add esi,1;"//zwiekszamy adres
"mov eax,[esi];"//pobieramhy nast zznak
"cmp eax,'\0';"
"je zapisz_do_bufora;"
"cmp eax,' ';"
"je spacja_wykryta_2;"
"mov eax,[esp+8];"
"cmp eax,0;"
"je etykieta_x;"
"jmp zapisz_do_bufora;"
"spacja_wykryta_2:"
"mov eax,1;"
"mov [esp+8],eax;"
"jmp iteruj_dalej;"
"zapisz_do_bufora:"
"mov eax,[esp+4];"
"interuj_po_slowie:"
"mov edx,[eax];"
"cmp edx,' ';"
"je etykieta_x;"
"cmp edx, '\0';"
"je etykieta_x;"
"mov [ebx],edx;"
"add eax,1;"
"add ebx,1;"
"jmp iteruj_po_slowie;"
"koniec:"
"pop edi;" //zdejmuje ze stosu
"pop ecx;"
"pop eax;"
"pop ebp;"
"ret;" //wyjdzie z funkcji
"wyjscie:"
".att_syntax_prefix;"
:
:"r"(x), "r"(y), "r"(bufor)
:"eax", "ecx"
);
return 0;
}
and here is the ideone link : http://ideone.com/wHFeDK
Someone know what may be wrong ? Thanks for help.
It's a horrible hack to manually switch syntax mode in inline asm and it might not work if you have any argument substitutions. The correct way is to use -masm=intel if you want intel syntax.
That said, your problem is that you have a typo in the directive where you wanted to restore the mode: you have .att_syntax_prefix instead of .att_syntax prefix (notice you don't need another underscore before prefix).
Also, the '\0' won't work, you should just use 0.
And, you have a typo: interuj_po_slowie vs iteruj_po_slowie.
PS: Stackoverflow is an english language forum, please post code in english, and comment it properly.

How to pass variables to intel format inline asm code compiled with gcc

I would like to ask some help form You! I have a project with a lot of C source. Most of them compiled with gcc, but some compiled with Intel compiler. This later codes have a lot of inline asm codes in Microsoft's MASM format. I would like to compile the whole project with gcc and modify as few code as I can. So I wrote a perl script which converts the intel format inline asm to GAS format. (BTW: I compile to 32 bit on a 64 bit Linux machine).
My problem that I have to specify for gcc that in the inline asm("...") which C variables are passed to the code adding the :: [var1] "m" var1, [var2] "m" var2, ... line at the end.
Is it a way to avoid this explicit specification?
My tryings:
The dummy test C code is simply replaces 4 characters the destination char array with the elements of the source char array (I know this is not the best way to do it. It is just a stupid example).
In the original function there is no explicit specification, but it can be compiled with Intel compiler (shame on me, but I did not test this, but it should work with Intel compiler as I made it based on the real code). LOOP label is used a lot of times, even in the same C source file.
#include <stdio.h>
void cp(char *pSrc, char *pDst) {
__asm
{
mov esi, pSrc
mov edi, pDst
mov edx, 4
LOOP:
mov al, [esi]
mov [edi], al
inc esi
inc edi
dec edx
jnz LOOP
};
}
int main() {
char src[] = "abcd";
char dst[] = "ABCD";
cp(src, dst);
printf("SRC: '%s', DST: '%s'\n", src, dst);
return 0;
}
Result is: SRC: 'abcd', DST: 'abcd'
The working converted cp code is (compiled with gcc).
GAS (AT&T) format (compiled: gcc -ggdb3 -std=gnu99 -m32 -o asm asm.c)
void cp(char *pSrc, char *pDst) {
asm(
"mov %[pSrc], %%esi\n\t"
"mov %[pDst], %%edi\n\t"
"mov $4, %%edx\n\t"
"LOOP%=:\n\t"
"mov (%%esi), %%al\n\t"
"mov %%al, (%%edi)\n\t"
"inc %%esi\n\t"
"inc %%edi\n\t"
"dec %%edx\n\t"
"jnz LOOP%=\n\t"
: [pDst] "=m" (pDst)
: [pSrc] "m" (pSrc)
: "esi", "edi", "edx", "al"
);
}
Intel format (compiled: gcc -ggdb3 -std=gnu99 -m32 -masm=intel -o asm asm.c)
void cp(char *pSrc, char *pDst) {
asm(".intel_syntax noprefix\n\t");
asm(
"mov esi, %[pSrc]\n\t"
"mov edi, %[pDst]\n\t"
"mov edx, 4\n\t"
"LOOP%=:\n\t"
"mov al, [esi]\n\t"
"mov [edi], al\n\t"
"inc esi\n\t"
"inc edi\n\t"
"dec edx\n\t"
"jnz LOOP%=\n\t"
: [pDst] "=m" (pDst)
: [pSrc] "m" (pSrc)
: "esi", "edi", "edx", "al"
);
asm(".intel_syntax prefix");
}
Both codes are working, but it needs some code modification (inserting the '%' characters, collecting the variables, modifying the jump labels and jump functions).
I also tried this version:
void cp(char *pSrc, char *pDst) {
asm(".intel_syntax noprefix\n\t");
asm(
"mov esi, pSrc\n\t"
"mov edi, pDst\n\t"
"mov edx, 4\n\t"
"LOOP:\n\t"
"mov al, [esi]\n\t"
"mov [edi], al\n\t"
"inc esi\n\t"
"inc edi\n\t"
"dec edx\n\t"
"jnz LOOP\n\t"
);
asm(".intel_syntax prefix");
}
But it drops
gcc -ggdb3 -std=gnu99 -masm=intel -m32 -o ./asm.exe ./asm.c
/tmp/cc2F9i0u.o: In function `cp':
/home/TAG_VR_20130311/vr/vr/slicecodec/src/./asm.c:41: undefined reference to `pSrc'
/home/TAG_VR_20130311/vr/vr/slicecodec/src/./asm.c:41: undefined reference to `pDst'
collect2: ld returned 1 exit status
Is there a way to avoid the definition of the input arguments and avoid the modifications of local labels?
ADDITION
I tried to use global variable. For this g constrain has to be used instead of m.
char pGlob[] = "qwer";
void cp(char *pDst) {
asm(".intel_syntax noprefix\n\t"
"mov esi, %[pGlob]\n\t"
"mov edi, %[pDst]\n\t"
"mov edx, 4\n\t"
"LOOP%=:\n\t"
"mov al, [esi]\n\t"
"mov [edi], al\n\t"
"inc esi\n\t"
"inc edi\n\t"
"dec edx\n\t"
"jnz LOOP%=\n\t"
".intel_syntax prefix" : [pDst] "=m" (pDst) : [pGlob] "g" (pGlob)
: "esi", "edi", "edx", "al");
}
ADDITION#2
I tried
"lea esi, pGlob\n\t" // OK
"lea esi, %[_pGlob]\n\t" // BAD
//"lea esi, pGlob_not_defined\n\t" // BAD
//gcc failed with: undefined reference to `pGlob_not_defined'
compiled to
lea esi, pGlob
lea esi, OFFSET FLAT:pGlob // BAD
//compilation fails with: Error: suffix or operands invalid for `lea'
It seems that only function local variables has to be defined. Global variable may be added to the trailer, but not really necessary. Both are working:
"mov esi, pGlob\n\t" // OK
"mov esi, %[_pGlob]\n\t" // OK
compiled to
mov esi, OFFSET FLAT:pGlob
mov esi, OFFSET FLAT:pGlob
I defined a function local variable. It has to be defined in the constraint part:
void cp(char *pDst) {
char pLoc[] = "yxcv";
asm(".intel_syntax noprefix\n\t"
...
//"mov esi, pLoc\n\t" // BAD
"mov esi, %[_pLoc]\n\t" // OK, 'm' BAD
...
".intel_syntax prefix" : [_pDst] "=m" (pDst) : [_pLoc] "g" (pLoc)
: "esi", "edi", "edx", "al");
Unfortunately it should be determined what are the global and what are the local variables. It is not easy as the asm code can be defined in C macros and even the surrounding function is not definite. I think only the precompiler has enough information to this. Maybe the code has to be precompiled with gcc -E ....
I realized that not defining the output in the constraint part, some code can be eliminated by the optimizer.
TIA!
Yes, you do need to specify the registers explicitly. GCC will not do that for you. And you can't (generally) put C variable names inside the ASM string.
Your final code block looks perfectly good, to me, but in GCC you don't need to choose which registers to use yourself. You should also use the volatile keyword to prevent the compiler thinking the code doesn't do anything given that it has no outputs.
Try this:
char pGlob[] = "qwer";
void cp(char *pDst) {
asm volatile (".intel_syntax noprefix\n\t"
"mov edx, 4\n\t"
"LOOP%=:\n\t"
"mov al, [%[pGlob]]\n\t"
"mov [%[pDst]], al\n\t"
"inc %[pGlob]\n\t"
"inc %[pDst]\n\t"
"dec edx\n\t"
"jnz LOOP%=\n\t"
".intel_syntax prefix" :: [pGlob] "g" (pGlob), [pDst] "g" (pDst) : "edx");
}
This way the compiler deals with loading the variables and chooses the registers for you (thereby eliminating a pointless copy from one register to another). Ideally you'd also eliminate the explicit use of edx, but it's not really necessary here.
Of course, in this silly example I would just recode the whole thing in C and let the compiler do its job.

Resources