LINUX.ORG.RU

[gcc + inline asm] привязка к регистрам


1

1

пробую использовать inline asm в gcc, например есть такой макрос:

#define __syscall3a( name, a,b,c ) ({\
	unsigned long ret;\
	__asm__ __volatile__(\
		"syscall" : "=a"(ret) :\
		"a"(__NR_##name),"D"(a),"S"(b),"d"(c) :\
		"memory","cc","r11","cx");\
	(long int)ret; })

это системный вызов с тремя параметрами, по идее всё предусмотрено и выполняется корректно, но не всегда. иногда gcc/gas подбирает другие регистры для name,a,b или c, а нужны именно указанные в строке входных регистров... попробовал ещё такой вариант кода:

#define __syscall3b( name, a,b,c ) ({\
	unsigned long ret;\
	register long int _n __asm__("%rax") = (long int)(__NR_##name);\
	register long int _a __asm__("%rdi") = (long int)(a);\
	register long int _b __asm__("%rsi") = (long int)(b);\
	register long int _c __asm__("%rdx") = (long int)(c);\
	__asm__ __volatile__(\
		"syscall" : "=a"(ret) :\
		"r"(_n),"r"(_a),"r"(_b),"r"(_c) :\
		"memory","cc","r11","cx");\
	(long int)ret; })

тоже работает корректно, НО иногда при компиляции получаю ошибку: «error: can't find a register in class ‘AREG’ while reloading ‘asm’»

подскажите, если ли варианты улучшить ситуацию с инлайном в данных случаях, кроме отказа от него? может быть существуют какие-нибудь «хитрые» ключики компиляции?


нашел таки способ, если кому интересно, вот код:

#define __syscall_f inline __attribute__((__always_inline__))
__syscall_f long __syscall6c( nr, a, b, c, d, e, f ) {
	unsigned long r;
	register long _d __asm__("%r10") = (long)(d);
	register long _e __asm__("%r8") = (long)(e);
	register long _f __asm__("%r9") = (long)(f);
	__asm__ __volatile__(
		"syscall" : "=a"(r) :
		"a"(nr),"D"(a),"S"(b),"d"(c),"r"(_d),"r"(_e),"r"(_f):
		"memory","cc","r11","cx");
	return (long)r;
}

mrs
() автор топика

> но не всегда. иногда gcc/gas подбирает другие регистры для name,a,b или c, а нужны именно указанные в строке входных регистров...

Слабо верится. Можешь показать тест-кейз, когда наступает «не всегда»?

anonymous
()
Ответ на: комментарий от anonymous

выпадал какой-то один регистр, вроде... попробую восстановить тест.

mrs
() автор топика
Ответ на: комментарий от anonymous

...видимо это я тогда ошибся с одним моментом... дело в том, что изменив последовательность строк в исходнике, у меня изменился и дамп немного:

  4000f0:       48 83 ec 08             sub    $0x8,%rsp
  4000f4:       48 c7 c7 ff ff ff ff    mov    $0xffffffffffffffff,%rdi
  4000fb:       48 c7 c0 ff ff ff ff    mov    $0xffffffffffffffff,%rax
  400102:       48 c7 c6 ff ff ff ff    mov    $0xffffffffffffffff,%rsi
  400109:       41 b8 02 00 00 00       mov    $0x2,%r8d
  40010f:       bf 01 00 00 00          mov    $0x1,%edi
  400114:       be 02 00 00 00          mov    $0x2,%esi
  400119:       ba 03 00 00 00          mov    $0x3,%edx
  40011e:       44 89 c0                mov    %r8d,%eax
  400121:       0f 05                   syscall

инструкцию по адресу H400109 я тогда посчитал ошибочной, не увидев что %r8d всего лишь вспомогательный регистр, хотя компилятор ранее его не использовал, помещая 0x2 сразу в %eax.

вот соответвующий сишник

long int a=1, b=2, c=3;
long int d;
__asm__ __volatile__ ( "movq $-1, %%rdi" ::: "%rdi" );
__asm__ __volatile__ ( "movq $-1, %%rax" ::: "%rax" );
__asm__ __volatile__ ( "movq $-1, %%rsi" ::: "%rsi" );

d = __syscall3a( open, a,b,c );
.
.

компилировал с ключиками "-Wall -O3 -nostdlib -fno-builtin".

в общем, первый вариант в первом посте, наверное, без ошибок. но, я пока остановился на третьем, так как он более удобный и менее опасный, imho.

mrs
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.