1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#ifndef RLD
24#include <string.h>
25#include <mach-o/ldsyms.h>
26#include <mach-o/getsect.h>
27#ifndef __OPENSTEP__
28#include <crt_externs.h>
29#else /* defined(__OPENSTEP__) */
30#ifdef __DYNAMIC__
31#include "mach-o/dyld.h" /* defines _dyld_lookup_and_bind() */
32#endif
33
34#if !defined(__DYNAMIC__)
35#define DECLARE_VAR(var, type) \
36extern type var
37#define SETUP_VAR(var)
38#define USE_VAR(var) var
39#else
40#define STRINGIFY(a) # a
41#define DECLARE_VAR(var, type)	\
42static type * var ## _pointer = 0
43#define SETUP_VAR(var)						\
44if ( var ## _pointer == 0) {				\
45    _dyld_lookup_and_bind( STRINGIFY(_ ## var),		\
46                           (uint32_t *) & var ## _pointer, 0);	\
47}
48#define USE_VAR(var) (* var ## _pointer)
49#endif
50#endif /* __OPENSTEP__ */
51
52/*
53 * This routine returns the highest address of the segments in the program (NOT
54 * the shared libraries).  It is intended to be used as a stop gap for programs
55 * that make UNIX style assumptions about how memory is allocated.  Typicly the
56 * asumptions under which this is used is that memory is contiguously allocated
57 * by the program's text and data from address 0 with no gaps.  The value of
58 * this differs from the value of &_end in a UNIX program in that this routine
59 * returns the address of the end of the segment not the end of the last section
60 * in that segment as would be the value of the symbol &_end.
61 */
62unsigned long
63get_end(void)
64{
65#ifndef __LP64__
66
67    struct segment_command *sgp;
68    unsigned long _end;
69    uint32_t i;
70#ifndef __OPENSTEP__
71    struct mach_header *mhp = _NSGetMachExecuteHeader();
72#else /* defined(__OPENSTEP__) */
73    static struct mach_header *mhp = NULL;
74	DECLARE_VAR(_mh_execute_header, struct mach_header);
75	SETUP_VAR(_mh_execute_header);
76
77	mhp = (struct mach_header *)(& USE_VAR(_mh_execute_header));
78#endif /* __OPENSTEP__ */
79	_end = 0;
80	sgp = (struct segment_command *)
81	      ((char *)mhp + sizeof(struct mach_header));
82	for(i = 0; i < mhp->ncmds; i++){
83	    if(sgp->cmd == LC_SEGMENT)
84		if(sgp->vmaddr + sgp->vmsize > _end)
85		    _end = sgp->vmaddr + sgp->vmsize;
86	    sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
87	}
88	return(_end);
89
90#else /* defined(__LP64__) */
91
92    struct mach_header_64 *mhp = _NSGetMachExecuteHeader();
93    struct segment_command_64 *sgp;
94    unsigned long _end;
95    uint32_t i;
96
97	_end = 0;
98	sgp = (struct segment_command_64 *)
99	      ((char *)mhp + sizeof(struct mach_header_64));
100	for(i = 0; i < mhp->ncmds; i++){
101	    if(sgp->cmd == LC_SEGMENT_64)
102		if(sgp->vmaddr + sgp->vmsize > _end)
103		    _end = sgp->vmaddr + sgp->vmsize;
104	    sgp = (struct segment_command_64 *)((char *)sgp + sgp->cmdsize);
105	}
106	return(_end);
107
108#endif /* defined(__LP64__) */
109}
110
111/*
112 * This returns what was the value of the UNIX link editor defined symbol
113 * _etext (the first address after the text section).  Note this my or may not
114 * be the only section in the __TEXT segment.
115 */
116unsigned long
117get_etext(void)
118{
119#ifndef __LP64__
120    const struct section *sp;
121#else /* defined(__LP64__) */
122    const struct section_64 *sp;
123#endif /* defined(__LP64__) */
124
125	sp = getsectbyname(SEG_TEXT, SECT_TEXT);
126	if(sp)
127	    return(sp->addr + sp->size);
128	else
129	    return(0);
130}
131
132/*
133 * This returns what was the value of the UNIX link editor defined symbol
134 * _edata (the first address after the data section).  Note this my or may not
135 * be the last non-zero fill section in the __DATA segment.
136 */
137unsigned long
138get_edata(void)
139{
140#ifndef __LP64__
141    const struct section *sp;
142#else /* defined(__LP64__) */
143    const struct section_64 *sp;
144#endif /* defined(__LP64__) */
145
146	sp = getsectbyname(SEG_DATA, SECT_DATA);
147	if(sp)
148	    return(sp->addr + sp->size);
149	else
150	    return(0);
151}
152#endif /* !defined(RLD) */
153