x86, win32의 빈 프로그램에 대한 GCC 어셈블리 출력
stackoverflow 코더의 지옥을 짜증나게 하기 위해 빈 프로그램을 쓰고 있지 않다.나는 단지 gnu 툴체인을 탐색하고 있을 뿐이다.
다음 내용은 너무 복잡할 수 있지만, 빈 프로그램 이야기를 계속하기 위해 C 컴파일러의 출력, 즉 GNU가 소비하는 것을 조사하기 시작했습니다.
gcc version 4.4.0 (TDM-1 mingw32)
test.c:
int main()
{
return 0;
}
gcc - S test.c
.file "test.c"
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
call ___main
movl $0, %eax
leave
ret
여기서 무슨 일이 일어나는지 설명해 주시겠어요?여기 그것을 이해하기 위한 나의 노력이 있다.사용하였습니다.as
x86 ASM:
.file "test.c"
는 논리 파일명의 지시어입니다..def
: 문서 "기호 이름에 대한 디버깅 정보 정의 시작"에 따르면기호(함수 이름/변수)는 무엇이며 어떤 종류의 디버깅 정보입니까?.scl
: docs는 "스토리지 클래스가 기호가 정적인지 외부인지 플래그를 표시할 수 있습니다."라고 말합니다.C에서 알 수 있는 정전기 및 외부기기와 같은 것입니까?2는 뭐야?.type
: "심볼 테이블엔트리의 유형 속성"으로 파라미터를 저장합니다.모르겠습니다.endef
: 문제 없습니다..text
이것은 문제가 되고 있습니다.섹션이라고 불리는 것 같고, 코드 위치라고 읽었는데, 의사 선생님께서 너무 많은 것을 알려주지 않았습니다..globl
"기호를 ld에 표시하십시오." 설명서는 이에 대해 매우 명확합니다._main:
주소도 있습니다.pushl_
: EBP " (32비트)"movl
이동 32살 C: 사c C:EBP = ESP;
andl
AND : 논리 AND. C: 사c C:ESP = -16 & ESP
이게 무슨 의미가 있는지 잘 모르겠어요call
를에 푸시 해), 다음의 장소에 합니다.IP 의 경우는, 「IP」를 참조해 주세요.__main
(_main? /_main?movl
: 이 이 0은 코드 끝에 반환되는 상수여야 합니다.MOV 을 0 、 EAX 、 MOV 。leave
후에 입력해 주세요.왜??ret
「」로 .「 」 。
도와주셔서 감사합니다!
.file "test.c"
.로 시작하는 명령어는 어셈블러에 대한 지시어입니다.이것은 "file.c"라고만 표시되며, exe의 디버깅 정보로 정보를 내보낼 수 있습니다.
.def __main; .scl 2; .type 32; .endef
.def 디렉티브는 디버깅 기호를 정의합니다.scl 2는 스토리지 클래스 2(스토리지 클래스)를 의미합니다.type 32는 이 섬볼이 함수라고 합니다.이러한 번호는 pe-coff exe 형식으로 정의됩니다.
__main은 gcc가 필요로 하는 부트스트래핑을 처리하는 함수입니다(c++ static initializer 실행 및 기타 필요한 하우스키핑 등).
.text
텍스트 섹션을 시작합니다. 코드가 여기에 있습니다.
.global_메인
는 _main 기호를 global로 정의하며 링커 및 링크되어 있는 다른 모듈에 표시됩니다.
.def _main; .scl 2; .type 32; .endef
_main과 마찬가지로 _main이 함수임을 나타내는 디버깅 기호를 만듭니다.디버거가 사용할 수 있습니다.
메인:
새 라벨을 시작합니다(주소가 됩니다).위의 .globl 지시어는 이 주소를 다른 엔티티에 표시합니다.
pushl %ebp
오래된 프레임 포인터(ebp 레지스터)를 스택에 저장합니다(이 기능이 종료되면 원래 위치로 되돌릴 수 있습니다).
movl %esp, %ebp
스택 포인터를 ebp 레지스터로 이동합니다.ebp는 종종 프레임 포인터라고 불리며, 현재의 "프레임"(일반적으로 함수) 내에서 스택 값의 상단을 가리킵니다(ebp를 통해 스택 상의 변수를 디버거에 사용할 수 있습니다).
및 l $16, %190
스택에 fffff0을 붙여서 실질적으로 16바이트 경계에 맞춥니다.스택의 정렬된 값에 대한 접근은 정렬되지 않은 값보다 훨씬 빠릅니다.위의 모든 명령어는 거의 표준 기능 프롤로그입니다.
call ___main
gcc에 필요한 초기화 작업을 수행하는 __메인 함수를 호출합니다.콜은 스택상의 현재 명령 포인터를 푸시하여 __main 주소로 점프합니다.
movl $0, %eax
0을 eax 레지스터로 이동합니다(반환 0의 0). eax 레지스터는 stdcall 호출 규약의 함수 반환 값을 유지하는 데 사용됩니다.
떠나
휴가 지시는 거의 의 줄임말이다.
movl ebp,esp popl ebp
즉, 기능을 시작할 때 수행된 작업을 "undos"하여 프레임 포인터와 스택을 이전 상태로 복원합니다.
리트
이 함수를 호출한 사용자로 돌아갑니다.스택에서 명령 포인터를 팝하고(해당 호출 명령이 거기에 배치됩니다) 점프를 합니다.
여기에서는, 매우 유사한 연습에 대해 설명합니다.http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax
대부분은 이해하셨을 겁니다.강조나 추가에 대해 메모하겠습니다.
__main
는 GNU 표준 라이브러리의 서브루틴으로 다양한 스타트업 초기화를 처리합니다.C 프로그램에는 반드시 필요한 것은 아니지만 C 코드가 C++와 연동되는 경우에 필요합니다.
_main
주요 서브루틴입니다.둘 다로서_main
그리고.__main
동일한 저장소 클래스 및 유형을 가진 코드 위치입니다.아직 정의를 못 내렸어요.scl
그리고..type
아직입니다. 몇 가지 글로벌 변수를 정의하면 어느 정도 빛을 얻을 수 있습니다.
첫 번째 세 가지 명령어는 스택프레임을 셋업하는 것입니다.이것은 서브루틴의 작업용 스토리지 기술 용어입니다.대부분 로컬 변수와 임시 변수입니다.밀어넣기ebp
는 발신자 스택프레임의 베이스를 저장합니다.놓는 것esp
ebp
스택 프레임의 베이스를 설정합니다.andl
얼라인먼트를 로 하는 SIMD 얼라인먼트는 의 얼라인먼트를 로 하지만 얼라인먼트는 16바이트의 통상 합니다).int
§float
s.
되면 기대하게 esp
로컬 변수에 스택스페이스를 할당하기 위해 메모리 아래로 이동합니다.의 ★★★★★★★★★★★★★★★★★.main
때문에 gcc는 상관없습니다.gcc 없 、 has 、 has 、 has has has has has 。
의 콜__main
는 메인 진입점에 특수하며 일반적으로 서브루틴에는 표시되지 않습니다.
나머지는 네가 추측한 대로다. ★★★★★eax
는, spec에 입니다. leave
하고, 「」를 실행해 주세요.ret
발신자에게 돌아갑니다.는 추가 매직 등)을 C 입니다.atexit()
프로세스의 종료 코드를 설정하고 운영체제에 프로세스 종료를 요청합니다.
그것에 대해 $16,%esp
- 32비트: -16(십진수)은 0xffffff0(16진수)과 같습니다.
- 64비트: -16(십진수)은 0xffffffffffffff0(16진수)과 같습니다.
따라서 ESP의 마지막 4비트(btw: 2**4는 16)를 마스크하고 다른 모든 비트를 유지합니다(타깃 시스템이 32비트인지 64비트인지에 관계없이).
★★★★★★★★에 대해서andl $-16,%esp
은 낮은 0으로 조정되기 때문에 %esp
x86에서는 스택의 가치가 낮아집니다.
내가 모든 답을 가진 것은 아니지만 내가 아는 것을 설명할 수 있다.
ebp
하기 위해 합니다.esp
흐름 중에 인수가 함수에 전달되는 위치와 자체 로컬 변수가 있는 위치를 참조합니다.입니다.ebp
pushl %ebp
하며, 을 자신의 위치인 「스택의 위치」, 「스택의 위치」로하는 것보다 esp
movl %esp, %ebp
의를 0으로 .ebp
이 시점에서는 GCC에 따라 다릅니다만, 이 컴파일러가 왜 그렇게 하는지 모르겠습니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★를 시작하겠습니다.call ___main
, __main은 입니까?는 많을 수 이 을 GCC와 함께0 으로 합니다.마지막으로 main()이 유일하게 하는 것은 반환값을 0으로 설정하는 것입니다.movl $0, %eax
★★★★★★★★★★★★★★★★★」leave
랑 똑같다movl %ebp, %esp; popl %ebp
원상 ebp
그 후 "displaces", "displaces"ret
완성할 수 있습니다. ret
eip
그 시점부터 스레드 플로우를 계속합니다(메인으로서 이 재시도에서는 프로그램의 끝을 처리하는 커널 프로시저가 발생할 가능성이 있습니다).
대부분은 스택 관리에 관한 것입니다.얼마 전에 스택의 사용법에 대한 자세한 튜토리얼을 썼는데, 그 이유를 설명하면 도움이 될 것 같습니다.근데 포르투갈어로...
언급URL : https://stackoverflow.com/questions/1317081/gccs-assembly-output-of-an-empty-program-on-x86-win32
'programing' 카테고리의 다른 글
Vue.js를 사용하여 대체 버튼을 클릭하여 대체 약품을 사용하고 싶다. (0) | 2022.08.19 |
---|---|
v-for 항목 내부 전환은 전체 목록에 영향을 미치는데, 각 전환이 포함된 목록 항목에만 영향을 미치도록 하려면 어떻게 해야 합니까? (0) | 2022.08.19 |
휴지 상태를 사용하여 기본 엔티티 속성 값을 설정하는 방법 (0) | 2022.08.19 |
Vue 2를 Vue 3으로 마이그레이션하는 중 오류:Vue는 생성자가 아닙니다. (0) | 2022.08.19 |
javadoc에서는 어떻게 @ 문자를 벗어날 수 있습니까? (0) | 2022.08.19 |