programing

Win32에서 GCC로 어셈블리 기호에 선행 밑줄을 추가하시겠습니까?

oldcodes 2023. 9. 11. 22:13
반응형

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가 요구하는 선행 밑줄을 생략하도록 설득하는 것입니다.

  • -fleading-underscore

    그 과 는 는 과 -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-underscoreELF 형식으로 컴파일할 때(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

반응형