LINK(5)

명칭
link - 다이나믹 로더와 링크 에디터 인터페이스

서식
<sys/types.h> <nlist.h> <link.h>

해설
인클루드 파일 <link.h> 그럼, 다이나믹하게 링크 된 프로그램이나 프로그램 라이브러리에 포함된다 여러종류의 구조체가 선언되고 있습니다. 그 구조체는, 링크 에디터와 로더 기구의 몇개의 원가요소간의 인터페이스를 정의합니다. 바이너리중에서의 이러한 구조체의 레이아웃은 많은 점으로 a.out 형식에 유사하고 있어, 심볼 정의 (부수 하는 캐릭터 라인 테이블을 포함한다)나 외부 엔티티에의 참조를 해결하는데 필요한 이전 레코드라고 한, 잘 닮은 기능을 제공합니다. 거기에 더해 다이나믹 로드와 링크 처리에 고유의 몇개의 데이터 구조도 기록하고 있습니다. 이러한 데이터 구조로서는, 링크 에디트 처리를 완결하는데 필요한 다른 오브젝트에의 참조나, 다른 프로세스간에 code page의 공유를 진행시키기 위한 위치 독립 코드 (Position Independent Code 생략해 PIC)(을)를 기능시키기 위한 간접 테이블이 있습니다. 여기서 말하는 데이터 구조 전체를 런타임 이전 섹션 (RRS) (이)라고 불러, 다이나믹하게 링크 되는 프로그램이나 공유 오브젝트의 표준 텍스트 및 데이터 세그먼트에 파묻힙니다. 이것은, 기존의 a.out(5) 형식에는 RRS 를 위한 장소가 그 밖에 없기 때문입니다.

어느 프로그램을 실행 가능으로 하는 처리가, system resource의 사용을 최적화하면서 올바르게 완료하도록, 복수의 유틸리티가 협조해 일합니다. 컴파일러는 PIC 코드를 출력해, 그리고 ld(1) 에 의해 공유 프로그램 라이브러리가 만들어집니다. 컴파일러는 또, 초기화되는 각 데이터 아이템의 사이즈 정보를 어셈블러 지시문 .size 를 이용해 기록합니다. PIC 코드는, 어느 간접 테이블을 통해서 데이터 변수에 액세스 하는 점으로 종래의 코드와 다르고 있습니다. 이 표는 글로벌 오프셋(offset) 테이블로 불려 관습에 의해, 예약명 _GLOBAL_OFFSET_TABLE_ 에 의해 액세스 가능합니다. 여기서 이용되는 메카니즘의 자세한 것은 기종 의존입니다만, 통상은 그 머신의 레지스터 1 개가 이 용도에 예약됩니다. 이러한 구조의 배경에 있는 합리성은, 실제의 로드 주소와는 독립한 코드를 생성하는 것입니다. 실행시에는, address 공간에 대해 여러가지 공유 오브젝트가 로드 되는 주소 에 응해, 글로벌 오프셋(offset) 테이블에 포함되는 값만 변경하면 좋습니다.

같이 포괄적으로 정의된 함수의 호출은, core image의 데이터 세그먼트중에 놓여져 있다 프로시저 링키지 테이블 (PLT)을 통해서 간접적으로 행해집니다. 이것도 또, 실행시에 텍스트 세그먼트(segment)를 수정하지 않고 끝마치기 위한 것입니다.

링크 에디터가 글로벌 오프셋(offset) 테이블과 프로시저 링키지 테이블을 배치하는 것은, 복수의 PIC 오브젝트 파일을 결합해 프로세스의 address 공간에 MAP 하는데 적합한 1 개의 이미지로 할 때입니다. 링크 에디터는 또, 실행시의 링크 에디터가 필요로 하는 모든 심볼을 모아 그것들을 이미지의 텍스트와 데이터의 비트열과 함께 스토어 합니다. 이제(벌써) 1 개의 예약 심볼 _DYNAMIC (은)는, 실행시의 링크 구조가 존재하는 것을 나타내는데 이용됩니다. _DYNAMIC 가 0 에 리로케이트 되는 경우는, 실행시 링크 에디터를 기동한다 필요는 없습니다. 만약 _DYNAMIC 가 비 0 이라면, _DYNAMIC 는, 필요한 이전 정보와 심볼 정보의 위치를 꺼낼 수가 있는 데이터 구조를 가리키고 있습니다. 이것은 특히, 스타트 업 모듈 crt0 그리고 이용됩니다. 관습으로서 _DYNAMIC 구조체는, 그것이 속하는 이미지의 데이터 세그먼트의 최초로 놓여집니다.

데이터 구조
다이나믹 링크와 실행시 이전을 서포트하는 데이터 구조는, 그러한 처리의 적용 대상 이미지의 텍스트 및 데이터 세그먼트의 양쪽 모두안에 있습니다. 텍스트 세그먼트(segment)에는 심볼 기술이나 이름이라고 하는 독해 전용 데이터가 포함되어 한편 데이터 세그먼트에는 이전 처리로 갱신할 필요가 있는 테이블류가 포함됩니다.

심볼 _DYNAMIC 는 _dynamic 구조체를 참조합니다:

    struct	_dynamic {
    	int	d_version;
    	struct 	so_debug *d_debug;
    	union {
    		struct section_dispatch_table *d_sdt;
    	} d_un;
    	struct  ld_entry *d_entry;
    };

d_version
    이 필드는 다른 버젼의 다이나믹 링크 실장용으로 제공되고 있습니다. ld(1) 및 ld.so(1) 하지만 이해하는 현재의 버젼 번호는, SunOS 4. x 릴리스로 이용되고 있다 LD_VERSION_SUN (3) 라고 FreeBSD 1.1 이래 사용되고 있다 LD_VERSION_BSD (8) 입니다.

d_un
    d_version 에 응한 데이터 구조를 참조합니다.

so_debug
    이 필드는, 공유 오브젝트의 심볼 테이블을 액세스하기 위한 훅을 디버거에 제공합니다. 이 공유 오브젝트는, 실행시 링크 에디터의 처리의 결과 로드 된 것입니다.

section_dispatch_table 구조체가 메인이 된다 “디스팻쳐” 테이블이며, 이미지내에서 여러가지 심볼 정보나 이전 정보가 놓여지는 세그먼트(segment)에의 오프셋(offset)를 보관 유지합니다.

    struct section_dispatch_table {
    	struct	so_map *sdt_loaded;
    	long	sdt_sods;
    	long	sdt_filler1;
    	long	sdt_got;
    	long	sdt_plt;
    	long	sdt_rel;
    	long	sdt_hash;
    	long	sdt_nzlist;
    	long	sdt_filler2;
    	long	sdt_buckets;
    	long	sdt_strings;
    	long	sdt_str_sz;
    	long	sdt_text_sz;
    	long	sdt_plt_sz;
    };

sdt_loaded
    로드 된 최초의 링크 MAP (후술)에의 포인터. 이 필드는 ld.so 에 의해 설정됩니다.

sdt_sods
    이 오브젝트가 필요로 하는 공유 오브젝트 기술자의 (링크) 리스트의 선두.

sdt_filler1
    사용하지 마세요 (SunOS 에서는 프로그램 라이브러리의 검색 룰을 지정하는데 사용되고 있었습니다).

sdt_got
    이 이미지중에서의 글로벌 오프셋(offset) 테이블의 위치.

sdt_plt
    이 이미지중에서의 프로시저 링키지 테이블의 위치.

sdt_rel
    실행시의 이전을 지정한다 relocation_info 구조체 ( a.out(5) 참조) 의 배열의 위치.

sdt_hash
    이 오브젝트의 심볼 테이블로 심볼 검색을 고속화하기 위한 해시 테이블의 위치.

sdt_nzlist
    심볼 테이블의 위치.

sdt_filler2
    현재 사용되고 있지 않습니다.

sdt_buckets
    sdt_hash 안의 버킷수.

sdt_strings
    sdt_nzlist 에 대응하는 심볼 캐릭터 라인 테이블의 위치.

sdt_str_sz
    캐릭터 라인 테이블의 사이즈.

sdt_text_sz
    이 오브젝트의 텍스트 세그먼트(segment)의 사이즈.

sdt_plt_sz
    프로시저 링키지 테이블의 사이즈.

sod 구조체는, 그것을 포함한 오브젝트의 링크 에디트 처리를 완료하는데 필요한 공유 오브젝트를 기술합니다. 그러한 오브젝트의 리스트 ( sod_next 그리고 연결됩니다) (은)는 section_dispatch_table 구조체의 sdt_sods 에 의해 지시해집니다.

    struct sod {
    	long	sod_name;
    	u_int	sod_library : 1,
    		sod_reserved : 31;
    	short	sod_major;
    	short	sod_minor;
    	long	sod_next;
    };

sod_name
    이 링크 오브젝트를 기술하는 캐릭터 라인의, 텍스트 세그먼트(segment)에 있어서의 오프셋(offset).

sod_library
    만약 설정되어 있으면, sod_name 하 ld.so 하지만 검색하게 되는 프로그램 라이브러리를 지정합니다. 그 패스명은, 어느 디렉토리군 ( ldconfig(8) 참조) 그리고 lib<sod_name>.so.n.m. 에 매치 하는 공유 오브젝트를 검색하는 것으로 얻을 수 있습니다. 만약 설정되어 있지 않으면, sod_name (은)는 희망하는 공유 오브젝트에 대한 풀 패스명을 지시할 필요가 있습니다.

sod_major
    로드 해야 할 공유 오브젝트의 메이저 버젼 번호를 지정합니다.

sod_minor
    로드 해야 할 공유 오브젝트의 희망하는 마이너 버젼 번호를 지정합니다.

프로세스의 address 공간에 로드 되는 공유 오브젝트 모두를 추적하기 위해서, 실행시 링크 에디터는 링크 MAP (으)로 불리는 구조체의 리스트를 관리하고 있습니다. 이러한 구조체는 실행시에게만 이용되어 실행 가능 파일이나 공유 프로그램 라이브러리의 텍스트 혹은 데이터 세그먼트에는 없습니다.

    struct so_map {
    	caddr_t	som_addr;
    	char 	*som_path;
    	struct	so_map *som_next;
    	struct	sod *som_sod;
    	caddr_t som_sodbase;
    	u_int	som_write : 1;
    	struct	_dynamic *som_dynamic;
    	caddr_t	som_spd;
    };

som_addr
    이 링크 MAP에 대응하는 공유 오브젝트가 로드 되는 주소.

som_path
    로드 되는 오브젝트의 풀 패스명.

som_next
    다음의 링크 MAP에의 포인터.

som_sod
    이 공유 오브젝트의 로드를 주관한다 sod 구조체.

som_sodbase
    장래의 버젼에 대해서는, 실행시 링커에게 건네집니다.

som_write
    이 오브젝트의 텍스트 세그먼트(segment) (의 일부분)가 현재 기입해 가능하다 경우에 세트 됩니다.

som_dynamic
    이 오브젝트의 _dynamic 구조체에의 포인터.

som_spd
    실행시 링크 에디터가 관리하는 프라이빗 데이터와 연결하기 위한 훅.

사이즈 첨부 심볼 기술. 이것은 단지 nlist 구조체에 필드 (nz_size) (을)를 1 개(살) 추가한 것입니다. 공유 오브젝트의 데이터 세그먼트에 있는 아이템의 사이즈 정보를 전달하는데 이용됩니다. 이 구조체의 배열은 공유 오브젝트의 텍스트 세그먼트(segment)에 존재해, 그 주소는 section_dispatch_table 의 sdt_nzlist 필드에서 지정됩니다.

    struct nzlist {
    	struct nlist	nlist;
    	u_long		nz_size;
    #define nz_un		nlist.n_un
    #define nz_strx		nlist.n_un.n_strx
    #define nz_name		nlist.n_un.n_name
    #define nz_type		nlist.n_type
    #define nz_value	nlist.n_value
    #define nz_desc		nlist.n_desc
    #define nz_other	nlist.n_other
    };

nlist
    ( nlist(3) 참조).

nz_size
    이 심볼로 표현되는 데이터의 사이즈.

실행시의 링크 에디트로 행해지는 심볼 검색을 고속화하기 위해(때문에), 공유 오브젝트의 텍스트 세그먼트(segment)에 해시 테이블이 포함되어 있습니다. section_dispatch_table 의 sdt_hash 필드는 rrs_hash 구조체를 지시합니다:

    struct rrs_hash {
    	int	rh_symbolnum;		/* 심볼 번호 */
    	int	rh_next;		/* 다음의 해시 엔트리 */
    };

rh_symbolnum
    공유 오브젝트의 심볼 테이블 ( ld_symbols 그리고 주어집니다)에서의 해당 심볼의 인덱스.

rh_next
    충돌이 일어났을 때, 이 필드는 이 해시 테이블의 버킷에 있어서의 다음의 엔트리의 오프셋(offset)를 보관 유지합니다. 최종 버킷 요소의 경우는 0 이 됩니다.
rt_symbol 구조체는, 실행시에 allocate 되는 코먼(commons)과 공유 오브젝트로부터 카피되는 데이터 아이템을 추적하는데 이용됩니다. 이러한 아이템은 링크 리스트로 관리되어 디버거에서의 이용을 위해서(때문에) so_debug 구조체 (후술) 중의 dd_cc 필드에 의해 공개됩니다.

    struct rt_symbol {
    	struct nzlist		*rt_sp;
    	struct rt_symbol	*rt_next;
    	struct rt_symbol	*rt_link;
    	caddr_t			rt_srcaddr;
    	struct so_map		*rt_smp;
    };

rt_sp
    심볼 기술.

rt_next
    다음의 rt_symbol 의 가상 주소.

rt_link
    해시 버킷에 있어서의 다음의 요소. ld.so 의 내부에서 이용됩니다.

rt_srcaddr
    공유 오브젝트중에서의 초기화제데이터의 소스 위치.

rt_smp
    이 실행시 심볼이 기술하는 데이터의 원래의 소스가 되는 공유 오브젝트.

so_debug 구조체는, 실행시 링크 에디트의 결과, 해당 프로세스의 address 공간에 로드 되었다 모든 공유 오브젝트의 정보를 얻기 위해서(때문에), 디버거에 의해 이용됩니다. 실행시 링크 에디터는 프로세스의 초기화 처리의 일부로서 실행되기 (위해)때문에, 공유 오브젝트로부터 심볼에 액세스 하려고 하는 디버거는, crt0 로부터 링크 에디터가 불린 다음에 마셔 그것이 가능해집니다. 다이나믹 링크 되고 있는 바이너리는 so_debug 구조체를 가지고 있습니다. 이 구조체의 장소는 _dynamic 안의 d_debug 필드에서 지시받습니다.

    struct 	so_debug {
    	int	dd_version;
    	int	dd_in_debugger;
    	int	dd_sym_loaded;
    	char    *dd_bpt_addr;
    	int	dd_bpt_shadow;
    	struct rt_symbol *dd_cc;
    };

dd_version
    이 인터페이스의 버젼 번호.

dd_in_debugger
    해당 프로그램이 디버거의 제어하에 있는 것을 실행시 링커에 알리기 위해서(때문에) 디버거에 의해 세트 됩니다.

dd_sym_loaded
    공유 오브젝트를 로드하는 것으로 실행시 링커가 심볼을 추가했을 경우, 실행시 링커에 의해 세트 됩니다.

dd_bpt_addr
    디버거에 제어를 옮기기 위해서(때문에) 실행시 링커에 의해 세트 된다 breakpoint 주소. 이 주소는, _main 호출 전에, 스타트 업 모듈 crt0.o 에 의해 있는 적절한 장소로 결정됩니다.

dd_bpt_shadow
    주소 dd_bpt_addr 에 있던 원래의 기계 인스트럭션을 보관 유지합니다. 디버거는, 프로그램 실행을 재개하기 전에 이 기계 인스트럭션을 바탕으로 되돌리는 것에 되어 있습니다.

dd_cc
    디버거가 필요로 할 가능성이 있는, 실행시에 allocate 한 심볼의 링크 리스트에의 포인터.

ld_entry 구조체는 ld.so 안의 서비스 routine 일식을 정의합니다.

    struct ld_entry {
    	void	*(*dlopen)(char *, int);
    	int	(*dlclose)(void *);
    	void	*(*dlsym)(void *, char *);
    	char	*(*dlerror)(void);
    };

crt_ldso 구조체는, crt0 중의 스타트 업 코드와 ld.so (와)과의 사이의 인터페이스를 정의합니다.

    struct crt_ldso {
    	int		crt_ba;
    	int		crt_dzfd;
    	int		crt_ldfd;
    	struct _dynamic	*crt_dp;
    	char		**crt_ep;
    	caddr_t		crt_bp;
    	char		*crt_prog;
    	char		*crt_ldso;
    	struct ld_entry	*crt_ldentry;
    };
    #define CRT_VERSION_SUN		1
    #define CRT_VERSION_BSD_2	2
    #define CRT_VERSION_BSD_3	3
    #define	CRT_VERSION_BSD_4	4

crt_ba
    crt0 에 의해 ld.so 하지만 로드 된 가상 주소.

crt_dzfd
    SunOS 에서는, 이 필드는 “/dev/zero” 에의 오픈된 파일 기술자를 보관 유지해, 0 클리어 된 디맨드 페이지를 얻습니다. FreeBSD 그럼 이 필드는 -1 을 보관 유지합니다.

crt_ldfd
    ld.so (을)를 로드하기 위해서(때문에) crt0 가 이용하는, 오픈된 파일 기술자 (을)를 보관 유지합니다.

crt_dp
    main 의 _dynamic 구조체에의 포인터.

crt_ep
    환경 캐릭터 라인에의 포인터.

crt_bp
    메인 프로그램이 디버거로 실행되는 경우, 실행시 링커가 breakpoint를 두는 주소. so_debug (을)를 참조해 주세요.

crt_prog
    crt0 로 결정되는 메인 프로그램의 이름 (CRT_VERSION_BSD3 마셔).

crt_ldso
    crt0 로 MAP 되는 실행시 링커의 패스 (CRT_VERSION_BSD4 마셔).

hints_header 구조체 및 hints_bucket 구조체는, 통상 “/var/run/ld.so.hints” 에 놓여지는 프로그램 라이브러리 힌트의 레이아웃을 정의합니다. 프로그램 라이브러리 힌트는, 파일 시스템중에서 공유 오브젝트 이미지의 있는 곳을 재빠르게 찾아내기 위해서(때문에) ld.so 에 의해 이용됩니다. 힌트 파일의 구성은 “a.out” (와)과 그만큼 다르지 않습니다. 즉 힌트 파일은, 고정장 해시 버킷의 오프셋(offset)와 사이즈를 결정하기 위한 헤더와 공통의 캐릭터 라인 풀을 가지고 있습니다.

    struct hints_header {
    	long		hh_magic;
    #define HH_MAGIC	011421044151
    	long		hh_version;
    #define LD_HINTS_VERSION_1	1
    	long		hh_hashtab;
    	long		hh_nbucket;
    	long		hh_strtab;
    	long		hh_strtab_sz;
    	long		hh_ehints;
    };

hh_magic
    힌트 파일의 magic number.

hh_version
    인터페이스의 버젼 번호.

hh_hashtab
    해시 테이블의 오프셋(offset).

hh_strtab
    캐릭터 라인 테이블의 오프셋(offset).

hh_strtab_sz
    캐릭터 라인 테이블의 사이즈.

hh_ehints
    힌트 파일로 이용 가능한 최대 오프셋(offset).

    /*
     * 힌트 파일의 해시 테이블 요소
     */
    struct hints_bucket {
    	int		hi_namex;
    	int		hi_pathx;
    	int		hi_dewey[MAXDEWEY];
    	int		hi_ndewey;
    #define hi_major hi_dewey[0]
    #define hi_minor hi_dewey[1]
    	int		hi_next;
    };

hi_namex
    프로그램 라이브러리를 지정하는 캐릭터 라인의 인덱스.

hi_pathx
    프로그램 라이브러리의 풀 패스명을 나타내는 캐릭터 라인의 인덱스.

hi_dewey
    공통 프로그램 라이브러리의 버젼 번호.

hi_ndewey
    hi_dewey 안의 유효 엔트리수.

hi_next
    해시 충돌때의 다음의 버킷.

경고
현재로서는, 공유 프로그램 라이브러리 생성을 서포트하고 있는 것은 (GNU) C 컴파일러 뿐입니다. 다른 프로그램 언어에서는 이용할 수 없습니다.