A.OUT(5)

명칭
a.out - 실행 가능 바이노리필드의 포맷

서식
<a.out.h>

해설
인클루드 파일 <a.out.h> 그럼 3 개의 구조체 물어 구두인가의 매크로가 선언되고 있습니다. 이러한 구조체는, 이 시스템으로 실행 가능한 기계어 코드 파일 (‘바이너리’) 의 포맷을 규정합니다.

바이노리필드는 최대로 7 개의 섹션으로부터 구성됩니다. 이러한 섹션을 순서에 주면(자) 이하와 같이 됩니다:

exec 헤더
    바이노리필드를 메모리상에 로드해 실행하기 위해서 커널이 이용하는 파라미터를 포함하고 있습니다. 이러한 파라미터는 링크 에디터 ld(1) 하지만 바이노리필드를 다른 바이노리필드와 결합할 때에도 이용됩니다. 이 섹션은 유일한 필수 섹션입니다.

텍스트 세그먼트(segment)
    프로그램이 실행될 때에 메모리상에 로드 된다 기계어 코드 및 관련 데이터를 포함하고 있습니다. 읽기 전용으로 로드 되는 경우가 있습니다.

데이터 세그먼트
    초기화제데이터를 포함하고 있습니다. 항상 기입해 가능한 메모리상에 로드 됩니다.

텍스트 이전
    바이노리필드 결합시에 텍스트 세그먼트(segment)내의 포인터를 수정하기 위해서, 링크 에디터에 의해 이용되는 레코드를 포함하고 있습니다.

데이터 이전
    전출의 텍스트 이전 섹션과 닮아 있습니다만, 데이터 세그먼트내의 포인터 수정용입니다.

심볼 테이블
    바이노리필드간에 이름 첨부의 변수나 함수 (‘심볼’) 의 주소 상호 참조를 해결하기 위해서, 링크 에디터에 의해 이용되는 레코드를 포함하고 있습니다.

string table
    심볼명에 대응하는 캐릭터 라인을 포함하고 있습니다.

모든 바이노리필드는 다음의 exec 구조체로 시작됩니다:

    struct exec {
    	unsigned long	a_midmag;
    	unsigned long	a_text;
    	unsigned long	a_data;
    	unsigned long	a_bss;
    	unsigned long	a_syms;
    	unsigned long	a_entry;
    	unsigned long	a_trsize;
    	unsigned long	a_drsize;
    };

이러한 필드는 이하의 기능을 가지고 있습니다:

a_midmag
    이 필드는 호스트의 바이트순서 (host byte-order)로 격납됩니다. 이 필드는 몇개의 서브 컴퍼넌트를 가지고 있어 그것들은 이하의 매크로 N_GETFLAG(), N_GETMID(), N_GETMAGIC() 그리고 참조되어 매크로 N_SETMAGIC() 그리고 설정됩니다.

    매크로 N_GETFLAG() (은)는 이하의 플래그를 돌려줍니다:

    EX_DYNAMIC
        이 실행 가능 파일이 런타임 링크 에디터의 서비스를 요구하는 것을 가리킵니다.

    EX_PIC
        이 오브젝트 파일이 위치 독립 (position independent)인 코드를 포함하고 있는 것을 나타냅니다. 이 플래그는 ‘-k’ 플래그 지정시에 as(1) 에 의해 설정되어 필요하면 ld(1) (은)는 이것을 보존합니다.

    EX_DYNAMIC 와 EX_PIC 의 양쪽 모두가 세트 되고 있는 경우, 그 오브젝트 파일은 위치 독립인 실행 가능 이미지입니다 (예: 공유 프로그램 라이브러리). 이것은 런타임 링크 에디터에 의해 프로세스의 address 공간에 로드 됩니다.

    매크로 N_GETMID() (은)는 머신 식별 코드 (machine-id)를 돌려줍니다. 이것은, 바이노리필드가 실행되어야 할 머신을 나타내고 있습니다.

    N_GETMAGIC() (은)는 magic number를 나타냅니다. magic number는 바이노리필드 종별을 일의에 식별해, 여러가지 로드 방법을 구별합니다. 이 필드는 이하의 값의 어느쪽이든 1 개(살)을 포함하지 않으면 안됩니다:

    OMAGIC
        텍스트 세그먼트(segment)와 데이터 세그먼트는 헤더의 직후에 있어, 연속하고 있습니다. 커널은 텍스트/데이터 세그먼트의 양쪽 모두를 기입해 가능 메모리 area에 로드합니다.

    NMAGIC
        OMAGIC (와)과 같이, 텍스트/데이터 세그먼트는 헤더의 직후에 있어, 연속하고 있습니다. 그러나, 커널은 텍스트 세그먼트(segment)를 읽어들여 전용 메모리 area에 로드해, 텍스트에 계속되는 페이지 경계로부터 시작된다 기입 가능 메모리 area에 데이터 세그먼트를 로드합니다.

    ZMAGIC
        커널은 각각의 페이지를 필요에 따라서 바이너리로부터 로드합니다. 헤더, 텍스트 세그먼트(segment) 및 데이터 세그먼트는 모두, 페이지 사이즈의 배수의 크기가 되도록, 링크 에디터에 의해 패딩 됩니다. 커널이 텍스트 세그먼트(segment)로부터 로드한 페이지는 읽어들여 전용입니다만, 데이터 세그먼트로부터 로드한 페이지는 기입해 가능합니다.

a_text
    텍스트 세그먼트(segment)의 사이즈 (바이트 단위)를 보관 유지합니다.

a_data
    데이터 세그먼트의 사이즈 (바이트 단위)를 보관 유지합니다.

a_bss
    ‘bss 세그먼트(segment)’ 의 바이트수를 보관 유지합니다. 이 값은 커널이 최초의 break 치 (brk(2)) (을)를 데이터 세그먼트의 뒤로 설정하는데 이용됩니다. 커널은, 여기에 나타나는 사이즈의 기입 가능 메모리 area가 데이터 세그먼트의 뒤로 준비되어 그러한 초기 상태가 0 이 되도록(듯이), 프로그램을 로드합니다. ( bss = 심볼로 개시하는 블록 (block started by symbol))

a_syms
    심볼 테이블 섹션의 사이즈 (바이트 단위)를 보관 유지합니다.

a_entry
    커널이 바이노리필드를 로드한 후의, 프로그램의 엔트리 포인트의 메모리아드레스를 보관 유지합니다. 커널은, 이 주소에 있는 기계 인스트럭션으로부터 프로그램의 실행을 개시합니다.

a_trsize
    텍스트 이전 테이블의 사이즈 (바이트 단위)를 보관 유지합니다.

a_drsize
    데이터 이전 테이블의 사이즈 (바이트 단위)를 보관 유지합니다.

인클루드 파일 a.out.h 그럼, exec 구조체를 이용해 일관성을 테스트하거나 바이노리필드중의 섹션 오프셋(offset)를 알기 위한 매크로가 정의되고 있습니다.

N_BADMAG(exec)
    a_magic 필드에, 인식할 수 없는 값이 포함되어 있는 경우, 비 0 을 돌려줍니다.

N_TXTOFF(exec)
    바이노리필드에 있어서의 텍스트 세그먼트(segment)의 선두의 바이트 오프셋(offset)를 돌려줍니다.

N_SYMOFF(exec)
    심볼 테이블의 선두의 바이트 오프셋(offset)를 돌려줍니다.

N_STROFF(exec)
    캐릭터 라인 테이블의 선두의 바이트 오프셋(offset)를 돌려줍니다.

이전 레코드는, relocation_info 구조체로 규정되는 표준 포맷입니다:

    struct relocation_info {
    	int		r_address;
    	unsigned int	r_symbolnum : 24,
    			r_pcrel : 1,
    			r_length : 2,
    			r_extern : 1,
    			r_baserel : 1,
    			r_jmptable : 1,
    			r_relative : 1,
    			r_copy : 1;
    };

relocation_info 구조체의 각 필드는 이하와 같이 이용됩니다:

r_address
    링크 에디트가 필요한 포인터의 바이트 오프셋(offset)를 보관 유지합니다. 텍스트 이전 오프셋(offset)는 텍스트 세그먼트(segment)의 선두로부터, 데이터 이전 오프셋(offset)는 데이터 세그먼트의 선두로부터, 각각 계산합니다. 링크 에디터는 이 오프셋(offset)에 스토어 되고 있는 값을 가산해, 이 이전 레코드를 이용해 계산한 새로운 값으로 변환합니다.

r_symbolnum
    심볼 테이블에 있어서의 심볼 구조체의 순서 번호 ( 바이트 오프셋(offset) 가 아닙니다 )(을)를 보관 유지합니다. 링크 에디터는 이 심볼의 절대 주소를 해결한 후, 그 주소를 이전중의 포인터에 가산합니다. (만약 r_extern 비트가 서지 않으면 상황은 다릅니다. 이하를 참조해 주세요. )

r_pcrel
    만약 이 비트가 서 있으면, 링크 에디터는, PC 상대 애드레싱을 이용하는 기계어 인스트럭션의 일부이다 포인터를 갱신하고 있는 것과 가정합니다. 리로케이트 되는 포인터의 주소는, 실행중의 프로그램이 그것을 이용할 때에, 암묵적으로 그 값에 가산됩니다.

r_length
    포인터의 길이를 2 를 바닥으로 하는 대수로 나타낸 바이트 단위로 보관 유지합니다. 1 바이트디스프레이스먼트라면 0, 2 바이트디스프레이스먼트라면 1, 4 바이트디스프레이스먼트라면 2 가 됩니다.

r_extern
    이 이전이 외부 참조를 필요로 하고 있는 경우에 세트 됩니다. 링크 에디터는, 심볼 주소를 이용해 이 포인터를 갱신하지 않으면 안됩니다. r_extern 비트가 서지 않은 경우, 그 이전은 ‘로컬’ 입니다. 링크 에디터는, 심볼치의 변화가 아니고, 각 세그먼트(segment)의 로드 주소의 변화에 응해 포인터를 갱신합니다 (다만, r_baserel 도 세트 되고 있는 경우(후술)는 제외합니다). 이 경우, r_symbolnum 필드의 내용은 n_type 의 값이 됩니다(후술). 링크 에디터는, 이 형태 필드로부터, 리로케이트 되는 포인터가 어느 세그먼트(segment)를 가리키고 있는지의 정보를 얻습니다.

r_baserel
    세트 되고 있는 경우, r_symbolnum 필드에서 지정되는 경우와 같이, 이 심볼은 글로벌 오프셋(offset) 테이블에의 오프셋(offset)에 리로케이트 됩니다. 실행시에, 글로벌 오프셋(offset) 테이블중의, 이 오프셋(offset) 위치에 있다 엔트리가, 심볼의 주소를 가지도록(듯이) 세트 됩니다.

r_jmptable
    세트 되고 있는 경우, r_symbolnum 필드에서 지정되는 경우와 같이, 이 심볼은 프로시저 링키지 테이블에의 오프셋(offset)에 리로케이트 됩니다.

r_relative
    세트 되고 있는 경우, 이 이전은, 이 오브젝트 파일이 포함된다 이미지의 (실행시의) 로드 주소와의 상대치가 됩니다. 이런 종류의 이전은 공유 오브젝트에게만 나타납니다.

r_copy
    세트 되고 있는 경우, 이 이전 레코드는, 그 내용을 r_address 그리고 지정되는 위치에 카피해야 하는 심볼을 나타냅니다. 카피 처리는, 실행시의 링크 에디터에 의해, 공유 오브젝트중의 적절한 데이터 아이템으로부터 행해집니다.

심볼은 이름과 주소를 대응 짓습니다 (보다 일반적으로는, 캐릭터 라인을 값에 대응 짓습니다). 링크 에디터가 주소를 조절하기 위해(때문에), 절대치를 할당할 수 없을지는 심볼을 이용해 주소를 표현하지 않으면 되지 않습니다. 심볼은, 심볼 테이블중의 고정장의 레코드와 캐릭터 라인 테이블중의 가변장의 이름으로부터 완성됩니다. 심볼 테이블은 nlist 구조체의 배열입니다:

    struct nlist {
    	union {
    		char	*n_name;
    		long	n_strx;
    	} n_un;
    	unsigned char	n_type;
    	char		n_other;
    	short		n_desc;
    	unsigned long	n_value;
    };

이러한 필드는 이하와 같이 이용됩니다:

n_un.n_strx
    이 심볼의 이름의, 캐릭터 라인 테이블에서의 바이트 오프셋(offset)를 보관 유지합니다. 프로그램이 nlist(3) 함수를 이용해 심볼 테이블을 액세스 하는 경우, 이 필드는, 메모리중의 캐릭터 라인에의 포인터이다 n_un.n_name 필드로 옮겨집니다.

n_type
    링크 에디터가 심볼치의 갱신 방법을 결정하는데 이용됩니다. n_type 필드는, 비트 마스크를 이용한 3 개의 subfield로 나눌 수 있습니다. 링크 에디터는 N_EXT 비트가 세트 되고 있는 심볼을 ‘external’ 심볼로서 취급해, 다른 바이노리필드로부터의 참조를 허가합니다. N_TYPE 마스크는 링크 에디터에 필요한 비트를 선택합니다:

    N_UNDF
        미정도리 심볼. 링크 에디터는, 다른 바이노리필드중의 같은 이름의 외부 심볼을 찾아 이 심볼의 절대치를 결정하지 않으면 안됩니다. 특별한 경우로서 만약 n_value 필드가 비 0 으로, 링크 에디트 대상의 어느 바이노리필드도 이 심볼을 정의하고 있지 않는 경우, 링크 에디터는 이 심볼이 bss 세그먼트(segment)중의 주소이라고 간주, n_value 에 동일한 바이트수의 area를 예약합니다. 만약 이 심볼이 복수의 바이노리필드중에서 미정도리가 되고 있어 그러한 바이노리필드간에 사이즈가 차이가 나는 경우, 링크 에디터는 그러한 사이즈의 최대치를 선택합니다.

    N_ABS
        절대 심볼. 링크 에디터는 절대 심볼은 갱신하지 않습니다.

    N_TEXT
        텍스트 심볼. 이 심볼의 값은 텍스트 주소이며, 링크 에디터는 바이노리필드를 merge 할 때, 그 값을 갱신합니다.

    N_DATA
        데이터 심볼. N_TEXT (와)과 같습니다만, 데이터 주소를 나타냅니다. 텍스트 심볼 및 데이터 심볼의 값은, 파일 오프셋(offset)는 아니고 주소입니다. 파일 오프셋(offset)를 복원하기 위해서(때문에), 대응하는 섹션의 선두의 로드 주소를 찾아내 그것을 줄여 다음에 그 섹션의 오프셋(offset)를 가산할 필요가 있습니다.

    N_BSS
        bss 심볼. 텍스트 심볼이나 데이터 심볼과 닮아 있습니다만, 바이노리필드중에 대응하는 오프셋(offset)를 가지지 않습니다.

    N_FN
        파일명 심볼. 바이노리필드를 merge 할 때, 링크 에디터는 바이노리필드의 다른 심볼의 전에 이 심볼을 삽입합니다. 이 심볼의 이름은 링크 에디터에게 줄 수 있었던 파일명으로, 심볼의 값은 바이노리필드로부터 얻은 선두 텍스트 주소입니다. 파일명 심볼은 린크에디트 처리나 로드 처리에는 불필요합니다만, 디버거에는 유용한 정보입니다.

    N_STAB 마스크는 gdb(1) 등의 상징적 디버거에 필요한 비트를 선택합니다. 그 값은 stab(5) 에 나타나고 있습니다.

n_other
    이 필드는, n_type 필드에서 결정되는 세그먼트(segment)에 관해서, 그 심볼의 로케이션과는 독립했다 심볼의 특징에 관한 정보를 제공합니다. 현재로서는, n_other 필드의 하위 4 비트는 AUX_FUNC 혹은 AUX_OBJECT 의 어느쪽이든을 취합니다 (이러한 정의에 대해서는 <link.h> (을)를 참조해 주세요). AUX_FUNC (은)는 심볼이라고 부르기 시작해 가능한 함수를 관련 지어 한편, AUX_OBJECT (은)는 심볼과 데이터를 관련 짓습니다. 이러한 관련은 텍스트 세그먼트(segment)/데이터 세그먼트의 별도이다고는 무관계합니다. 이 필드는, ld(1) 하지만 동적인 실행 가능 형식을 구축하기 위해서 사용하는 것을 의도하고 있습니다.

n_desc
    디버거용으로 예약되고 있어 링크 에디터는 이 필드를 전혀 변경하지 않습니다. 디버거에 따라서 다른 목적으로 사용됩니다.

n_value
    심볼의 값을 보관 유지합니다. 텍스트, 데이터 및 bss 심볼의 경우, 그 값은 주소입니다. 다른 심볼 (예를 들면 디버거 심볼등 )의 경우, 그 값은 여러가지입니다.

캐릭터 라인 테이블은 unsigned long 형태의 길이와 거기에 계속되는 널 종단의 심볼 캐릭터 라인으로부터 완성됩니다. 이 길이는, 테이블 전체의 사이즈를 바이트 단위로 나타냅니다. 즉, 그 최소치 (바꿔 말하면, 최초의 캐릭터 라인의 오프셋(offset))는, 32 비트 머신에서는 항상 4 가 됩니다.

관련 항목
as(1), gdb(1), ld(1), brk(2), execve(2), nlist(3), core(5), elf(5), link(5), stab(5)

역사
인클루드 파일 a.out.h 하 AT&T UNIX 그리고 등장했습니다.

버그
반드시 모든 서포트 대상 아키텍쳐가 a_midmag 필드를 이용하는 것은 아니기 때문에, 어느 바이너리가 어떠한 아키텍쳐상에서 실행되는지는, 실제의 머신 코드를 조사하지 않는 한 판정 곤란한 가능성이 있습니다. 머신 ID 가 있었다고 해도, exec 헤더의 바이트순서는 머신 의존입니다.