The disassembly of your code looks like this (here in AT&T syntax):
jmp pos2
pos1:
pop %ebx
xor %eax,%eax
mov %al,dbyte1-data(%ebx)
mov %ebx,dlong1-data(%ebx)
mov %eax,dlong2-data(%ebx)
mov $0xb,%al
lea dlong1-data(%ebx),%ecx
lea dlong2-data(%ebx),%edx
int $0x80
pos2:
call pos1
data:
.ascii "xxx/aa/"
dbyte1:
.byte dont_care // ebx+dbyte1-data = ebx+7
dlong1:
.long dont_care // ebx+dlong1-data = ebx+8
dlong2:
.long dont_care // ebx+dlong2-data = ebx+0xC
.byte dont_care // "AAAA0"
First of all you can see that this code will run in an endless loop if the "execve" system call (I'm assuming 0xB is execve) will fail. Execve however will fail because "xxx/aa/" is not a valid file name. Seems the "mov %al,0x7(%ebx)" should really be "0x6(%ebx)".
As already written by "Giel" you may use the "strace" command to see if execve is really called with "xxx/aa/" instead of "xxx/aa" as file name.
Some note you should keep in mind for your next project (not for this one):
Most Linux executables have the "NX" bit set for the stack and data pages. This means that the CPU will not allow executing code from the stack or from data segments. This means that execution of shellcode would not work on most Linux programs but the program would be stopped with a bus exception or a similar exception.