Win32에서 GCC로 어셈블리 기호에 선행 밑줄을 추가하시겠습니까?
조립에 정의된 함수를 호출하는 C 코드 조각을 가지고 있습니다.예를 들어, fo.c가 다음을 포함한다고 가정해 보겠습니다.
int bar(int x); /* returns 2x */
int main(int argc, char *argv[]) { return bar(7); }
그리고 bar.s는 x86 어셈블리에서 bar()의 구현을 포함하고 있습니다.
.global bar
bar: movl 4(%esp), %eax
addl %eax, %eax
ret
리눅스에서 나는 이 소스들을 다음과 같이 쉽게 컴파일하고 GCC와 연결할 수 있습니다.
% gcc -o test foo.c bar.s
% ./test; echo $?
14
MinGW를 사용하는 Windows에서는 "'bar'에 대한 정의되지 않은 참조" 오류와 함께 실패합니다.이것의 원인은 윈도우에서 C 호출 규약을 가진 함수의 모든 식별자가 밑줄로 접두사가 붙지만, "bar"는 어셈블리에서 정의되기 때문에 이 접두사를 얻지 못하고 링크가 실패하기 때문입니다. (따라서 이 오류 메시지는 실제로 bar가 아니라 _bar 기호를 놓친 것에 대해 불평하고 있습니다.)
요약하자면:
% gcc -c foo.c bar.s
% nm foo.o bar.o
foo.o:
00000000 b .bss
00000000 d .data
00000000 t .text
U ___main
U _bar
00000000 T _main
bar.o:
00000000 b .bss
00000000 d .data
00000000 t .text
00000000 T bar
이제 문제는 어떻게 하면 이 문제를 잘 해결할 수 있을까 하는 것입니다.만약 내가 윈도우용으로만 글을 쓴다면, 나는 그저 밑줄을 bar.s의 식별자에 추가할 수 있지만, 리눅스에서는 코드가 끊어집니다.는 gc의본다이tgdeic이c본을는g's의-fleading-underscore
그리고.-fno-leading-underscore
옵션을 선택할 수 있지만 둘 다 (적어도 윈도우에서는) 아무것도 하지 않는 것 같습니다.
지금 내가 볼 수 있는 유일한 대안은 어셈블리 파일을 C 전처리기에 전달하고 WIN32가 정의된 경우 모든 선언된 기호를 수동으로 재정의하는 것이지만, 그것도 그리 좋지는 않습니다.
이것에 대한 깨끗한 해결책을 가지고 있는 사람이 있습니까?혹시 내가 감독한 컴파일러 옵션?어쩌면 GNU 어셈블러는 이 특정 기호가 C 호출 규약을 사용하는 함수를 가리키며 그렇게 망글링해야 한다는 것을 구체적으로 설명하는 방법을 지원할 수 있을까요?다른 생각 있나요?
한 가지 방법은 위험하긴 하지만 GCC가 ABI가 요구하는 선행 밑줄을 생략하도록 설득하는 것입니다.
그 과 는 는 과
-fno-leading-underscore
파일에 C 에 가 되는 을 합니다 로 의 합니다 로 을 되는 가 에 한 가지 용도는 레거시 어셈블리 코드와의 연동을 돕는 것입니다.경고:
-fleading-underscore
스위치는 GCC가 해당 스위치 없이 생성된 코드와 이진 호환되지 않는 코드를 생성하게 합니다.기본이 아닌 응용 프로그램 이진 인터페이스를 준수하는 데 사용합니다.일부 대상에서 이 스위치를 완벽하게 지원하는 것은 아닙니다.
또 다른 안전한 방법은 GCC에 사용할 이름을 명시적으로 말하는 것입니다.
5.39 어셈블러 코드에 사용되는 제어명
C 에 할 을 할 에 할 을
asm
(또는__asm__
) 다음과int foo asm ("myfoo") = 2;
에 할 을 합니다에 합니다.
foo
는 \"my foo \"my foo\" 합니다.' rather than the usual \``_foo
'.일반적으로 밑줄이 C 함수 또는 변수 이름 앞에 붙는 시스템에서는 이 기능을 사용하여 밑줄로 시작하지 않는 링커의 이름을 정의할 수 있습니다.
이러한 변수에는 어셈블러 이름이 없으므로 정적이 아닌 로컬 변수에 이 기능을 사용하는 것은 의미가 없습니다.변수를 특정 레지스터에 넣으려는 경우 명시적 규칙 변수를 참조하십시오.GCC는 현재 그러한 코드를 경고와 함께 받아들이지만, 아마도 추후 경고가 아닌 오류를 발행하도록 변경될 것입니다.
.
asm
함수 정의에서 이러한 방식으로; 그러나 함수의 정의 앞에 함수에 대한 선언을 작성하고 퍼팅을 함으로써 동일한 효과를 얻을 수 있습니다.asm
거기에, 다음과 같이.extern func () asm ("FUNC"); func (x, y) int x, y; /* ... */
선택한 어셈블리 이름이 다른 어셈블리 기호와 충돌하지 않도록 하는 것은 사용자에게 달려 있습니다.또한 레지스터 이름을 사용해서는 안 됩니다. 그러면 완전히 잘못된 어셈블리 코드가 생성됩니다.GCC는 아직 정적 변수를 레지스터에 저장할 수 있는 기능이 없습니다.아마 그것이 추가될 것입니다.
당신 같은 경우엔
extern int bar(int x) asm("bar");
""GCC는 """라고 말해야 합니다.bar
는 호출 함수임에도 불구하고 sm 이름 "bar"를 사용합니다.
C 전처리기를 사용하여 어셈블리를 전처리하고 매크로를 사용하여 Windows에서 누락된 밑줄을 추가할 수 있습니다.먼저 어셈블리 파일 이름을 bar.s에서 bar로 변경해야 합니다.S( 대문자 'S').이것은 gcc에게 파일을 전처리하기 위해 cpp를 사용하라고 알려줍니다.
누락된 밑줄을 추가하려면 다음과 같이 매크로 "cdecl"을 정의할 수 있습니다.
#if defined(__WIN32__)
# define cdecl(s) _##s
#else
# define cdecl(s) s
#endif
그러면 이렇게 사용합니다.
.global cdecl(bar)
cdecl(bar):
movl 4(%esp), %eax
addl %eax, %eax
ret
Mac OSX에서도 선두 밑줄이 필요하므로 다음과 같이 매크로의 첫 줄을 업데이트할 수 있습니다.
#if defined(__WIN32__) || defined(__APPLE__)
두 번 신고해 주실 수 있나요?
.global bar
.global _bar
한동안 어셈블리를 쓰지 않았는데 .global 식별자가 레이블처럼 작동하는 건가요?
ELF 대상 컴파일러는 기본적으로 선행 밑줄을 추가하지 않습니다.추가할 수 있습니다.-fleading-underscore
ELF 형식으로 컴파일할 때(Linux에서).makefile에 조건을 사용합니다.
참조 : http://opencores.org/openrisc,gnu_toolchain ("글로벌 이름을 변경하지 않은 상태로 유지"에 대한 검색을 온 페이지에서 수행)
JNI에서 이 문제가 발생했습니다. 예를 들어 Java Runtime 1.5/32Bit에서 external-C 함수에 대한 선행 밑줄이 예상됩니다."-addading-underscore"는 사용할 수 없습니다!
여기서 해결책은 선언된 함수에 대해 Java-Compiler에서 stub-header를 구문 분석하고 패턴 ´#define bar_bar`로 대체 정의를 도출하는 것이었습니다.
언급URL : https://stackoverflow.com/questions/1034852/adding-leading-underscores-to-assembly-symbols-with-gcc-on-win32
'programing' 카테고리의 다른 글
빠른 고정점 power, log, expand sqrt (0) | 2023.09.11 |
---|---|
N/2번 이상 반복되는 배열의 요소를 찾는 방법은? (0) | 2023.09.11 |
쿠키를이름으로삭제하시겠습니까? (0) | 2023.09.11 |
HyperLogLog 알고리즘은 어떻게 작동합니까? (0) | 2023.09.11 |
마리아드비 컨테이너 하나에만 연동된 Gitlab과 Wordpress 컨테이너 사용이 가능한가요? (0) | 2023.09.11 |