2010-01-13 7 views
3

컴파일 타임에 알 수없는 인수를 사용하여 함수를 호출해야하는 프로젝트에서 대규모 인라인 어셈블리를 사용합니다. 그리고 때때로 리눅스에서 작동하도록하기 위해 관리합니다. '이 t)는 그 문제가 기억 같은 이상한 일들이 일어날 :루프 내부의 인라인 어셈블리

내가 뭔가를 작동

for(int i = 1; i >= 0; i--) 
    asm("push %0"::"m"(someArray[i])); 

같은이있는 경우.

내가

for(int i = this->someVar; i >= 0; i--) 
    asm("push %0"::"m"(someArray[i])); 

이 나는의 somevar는이 세그먼트 오류가 발생합니다 값 1을 들고 내 인생을 보장합니다.

내가

int x = 1; 
for(int i = x; i >= 0; i--) 
    asm("push %0"::"m"(someArray[i])); 

이 또한 경우는

int x = this->someVar; 
for(int i = x; i >= 0; i--) 
    asm("push %0"::"m"(someArray[i])); 

하지 않고 작동합니다.

또한 이상하게도 일부 기능에서는 내가 가지고있는 다른 것들과 같은 문제를 가지고 있지 않지만 모두 같은 대상에 있다고 말할 수 있습니다.

문제가있는 부분을 해결할 수있는 정보를 누군가에게 알려 주면 감사하겠습니다.

for 루프에서 인수를 푸시해야하므로주의하지 않는 것이 좋습니다.

"휘발성"인라인 어셈블리 단어를 사용해 보았지만 아무 것도 변경되지 않았습니다.

+0

질문은 반드시 "배열 요소를 스택에 복사하는 대신 배열에 포인터를 전달하는 것이 좋을 것입니다"라고 질문해야합니다. 그렇지 않으면 무엇인가 놓치고 있습니까? 함께 : func (someArray, this-> someVar) 다음 성능 향상을 얻을 것이다 (아무 메모리 이동, 루프 없음) – Skizz

+0

내가 제어 할 수없는 함수를 호출하고 있습니다. 그들은 다른 도서관에 있습니다.나는 그들에게 그들이 기대하고있는 논증을 전달할 필요가있다. – user246100

+0

컴파일러의 손 아래에서 페어링되지 않은'push '를 수행하여 로컬 변수의 상대 위치를 변경하는 것은 매우 나쁜 생각입니다. – avakar

답변

4

나는 문제가 무엇 이해하지만

asm{ 
    loop1: 
    mov ax, this->var 
    ... 
    dec ax 
    cmp ax, 0 
    je exit 
    jmp loop1 
} 

과 동일한 분명 ASM 코드를 사용하여 코드를 작성하려고 할 수 ...

종료 :

또한

시도는 "VAR"를 만들기 위해 가치가 정적으로도 도움이 될 수 있습니다.

+0

코드가 어떻게 흐르기 때문에 정적 일 수 없습니다. 어셈블리 전용 코드로 만들려고합니다. 감사. – user246100

4

해체를 검사하십시오. 가장 큰 원인은 i 및/또는 최종 값을 보유하는 변수가 for 루프의 각 반복시 스택의 고정 오프셋에서 다시 채워지고 push이 스택 포인터를 컴파일러가 예상 한 지점에서 오프셋하고 그래서 잘못된 값을 가져옵니다.

당신은 (예를 들어, 지역 변수를 register 선언)의 다양한 해결 방법을 시도 할 수 있지만, 불행하게도이 경우 C/C에서 보증 올바른 행동 ++에 더 좋은 방법은 없습니다. 문제가 발생하지 않도록하려면 oivoodoo가 제안한 것처럼 직접 루프를 구현하십시오.

+0

감사합니다. oivoodoo 제안을 시도해 보겠습니다. – user246100

3

은 여기 내 심령 디버깅 노력의 :

ithis 가능성이 가장 높은 스택에 저장하고, 386 위로에, 기계 코드를 직접 esp -relative 메모리 위치를 참조 할 수 있습니다, 그래서 컴파일러는 잘 생성 할 수

mov eax,[esp+8] 

같은 지침은 eax 레지스터에 this의 값을 얻을 수 있습니다. 문제는 스택 포인터로 연산이 엉망이므로이 하드 코딩 된 액세스는 첫 번째 반복 이후에 잘못된 메모리 위치에 액세스합니다.

대부분의 경우, this->someVar이없는 단순한 루프 형식은 컴파일러에서보다 철저하게 최적화되므로 레지스터 만 사용하는 컴퓨터 코드가 생기고 esp- 관련 액세스가 없으므로 계속 정상적으로 작동합니다.

한 번에 로컬 변수와 인수에 대한 모든 메모리 액세스는 ebp 레지스터를 통해 이루어지며 인라인 어셈블리 코드에 의해 변경되지 않습니다. esp 대신 ebp을 사용하도록 컴파일러 스위치를 찾을 수 있으면 문제가 해결 될 수 있습니다.

경고 : 컴파일러는 스택을 엉망으로 만들 것을 기대하지 않습니다. 스택 맨 위를 항상 알고 있다고 예상합니다. 스택에있는 것들을 실제로 동적으로 푸시하고 싶다면 oivoodoo과 같이 루프 자체를 어셈블리 언어로 완전히 작성하는 것이 좋습니다.

+0

주제에 대한 지식이 없지만 내가 아는 바가 무엇이 일어나고 있는지 생각하게합니다. 유용한 코멘트 주셔서 감사합니다. – user246100

0

args의 수에 대한 제한을 알고있는 경우 실제 인수를 끝까지 정렬하여 인수 수만큼 단일 함수 호출로 호출 할 수 있습니다.

경고 : x86_64 abi는 일부 매개 변수에 대해 레지스터를 사용하므로이 코드와 코드도 손상됩니다.

+0

수는 무제한이며 나는 그와 같이되기를 원합니다. 나는 당신의 솔루션이 덜 효율적일 것이라고 생각합니다. 참조하는 x86_64 질문에 대해서는 응용 프로그램이 적용되지 않기 때문에 문제가되지 않습니다. – user246100

1

먼저 리눅스에서 gcc가 스택 포인터를 사용하지 않고 로컬 변수를 색인하기 위해 스택 포인터를 사용하고 있습니다. 이것은 gcc가 다른 범용 레지스터로 프레임 포인터 (BP Under x86)를 사용하고 프레임을 설정하는 많은 코드를 사용하지 않도록하는 최적화입니다. 프레임은 기본적으로 로컬 함수에 속하는 SP와 BP 사이의 영역입니다. 이 함수에 전달한 크기로 alloca를 호출하면 컴파일러가이 최적화를 수행하지 않기 때문에 모든 것이 더 좋아질 것입니다.

그 말은 버그는 정말로 당신의 코드에 있습니다. 실제로 무엇을하는지 알지 못한다면 인라인 asm을 입력했을 때와 다른 스택 포인터로 인라인 asm을 끝내면 안됩니다. 컴파일러는 거의 항상 스택 포인터를 독점적으로 소유한다고 생각합니다. 그들은 변수를 저장 한 위치를 찾기 위해 변수를 사용할 수 있도록 변수에 의존합니다. 또한 프레임 포인터 (BP)에서 멀리 떨어져 있어야합니다.

시간이 많이 걸리는 것은 드물기 때문에 일반적으로 컨텍스트 전환 코드 (한 스레드 또는 프로세스에서 다른 스레드로 변경)와 같은 경우에 해당합니다.

관련 문제