output,aout: Improve aout_section_names
[nasm.git] / nasmlib / file.c
blobe525c83a0c5d04ed08de767c483994129664377d
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2016 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
34 #include "compiler.h"
35 #include "nasmlib.h"
37 #include <errno.h>
39 #ifdef HAVE_FCNTL_H
40 # include <fcntl.h>
41 #endif
42 #ifdef HAVE_SYS_STAT_H
43 # include <sys/stat.h>
44 #endif
45 #ifdef HAVE_IO_H
46 # include <io.h>
47 #endif
48 #ifdef HAVE_UNISTD_H
49 # include <unistd.h>
50 #endif
51 #ifdef HAVE_SYS_MMAN_H
52 # include <sys/mman.h>
53 #endif
55 #if !defined(HAVE_FILENO) && defined(HAVE__FILENO)
56 # define HAVE_FILENO 1
57 # define fileno _fileno
58 #endif
60 #if !defined(HAVE_ACCESS) && defined(HAVE__ACCESS)
61 # define HAVE_ACCESS 1
62 # define access _access
63 #endif
64 #ifndef R_OK
65 # define R_OK 4 /* Classic Unix constant, same on Windows */
66 #endif
68 /* Can we adjust the file size without actually writing all the bytes? */
69 #ifdef HAVE_FILENO /* Useless without fileno() */
70 # ifdef HAVE__CHSIZE_S
71 # define nasm_ftruncate(fd,size) _chsize_s(fd,size)
72 # elif defined(HAVE__CHSIZE)
73 # define nasm_ftruncate(fd,size) _chsize(fd,size)
74 # elif defined(HAVE_FTRUNCATE)
75 # define nasm_ftruncate(fd,size) ftruncate(fd,size)
76 # endif
77 #endif
79 #ifdef HAVE__STATI64
80 # define HAVE_STAT 1
81 # define stat _stati64
82 #endif
84 void nasm_write(const void *ptr, size_t size, FILE *f)
86 size_t n = fwrite(ptr, 1, size, f);
87 if (n != size || ferror(f) || feof(f))
88 nasm_fatal(0, "unable to write output: %s", strerror(errno));
91 #ifdef WORDS_LITTLEENDIAN
93 void fwriteint16_t(uint16_t data, FILE * fp)
95 nasm_write(&data, 2, fp);
98 void fwriteint32_t(uint32_t data, FILE * fp)
100 nasm_write(&data, 4, fp);
103 void fwriteint64_t(uint64_t data, FILE * fp)
105 nasm_write(&data, 8, fp);
108 void fwriteaddr(uint64_t data, int size, FILE * fp)
110 nasm_write(&data, size, fp);
113 #else /* not WORDS_LITTLEENDIAN */
115 void fwriteint16_t(uint16_t data, FILE * fp)
117 char buffer[2], *p = buffer;
118 WRITESHORT(p, data);
119 nasm_write(buffer, 2, fp);
122 void fwriteint32_t(uint32_t data, FILE * fp)
124 char buffer[4], *p = buffer;
125 WRITELONG(p, data);
126 nasm_write(buffer, 4, fp);
129 void fwriteint64_t(uint64_t data, FILE * fp)
131 char buffer[8], *p = buffer;
132 WRITEDLONG(p, data);
133 nasm_write(buffer, 8, fp);
136 void fwriteaddr(uint64_t data, int size, FILE * fp)
138 char buffer[8], *p = buffer;
139 WRITEADDR(p, data, size);
140 nasm_write(buffer, size, fp);
143 #endif
146 void fwritezero(off_t bytes, FILE *fp)
148 size_t blksize;
150 #ifdef nasm_ftruncate
151 if (bytes >= BUFSIZ && !ferror(fp) && !feof(fp)) {
152 off_t pos = ftello(fp);
153 if (pos >= 0) {
154 pos += bytes;
155 if (!fflush(fp) &&
156 !nasm_ftruncate(fileno(fp), pos) &&
157 !fseeko(fp, pos, SEEK_SET))
158 return;
161 #endif
163 while (bytes > 0) {
164 blksize = (bytes < ZERO_BUF_SIZE) ? bytes : ZERO_BUF_SIZE;
166 nasm_write(zero_buffer, blksize, fp);
167 bytes -= blksize;
171 FILE *nasm_open_read(const char *filename, enum file_flags flags)
173 FILE *f;
174 bool again = true;
176 #ifdef __GLIBC__
178 * Try to open this file with memory mapping for speed, unless we are
179 * going to do it "manually" with nasm_map_file()
181 if (!(flags & NF_FORMAP)) {
182 f = fopen(filename, (flags & NF_TEXT) ? "rtm" : "rbm");
183 again = (!f) && (errno == EINVAL); /* Not supported, try without m */
185 #endif
187 if (again)
188 f = fopen(filename, (flags & NF_TEXT) ? "rt" : "rb");
190 if (!f && (flags & NF_FATAL))
191 nasm_fatal(ERR_NOFILE, "unable to open input file: `%s': %s",
192 filename, strerror(errno));
194 return f;
197 FILE *nasm_open_write(const char *filename, enum file_flags flags)
199 FILE *f;
201 f = fopen(filename, (flags & NF_TEXT) ? "wt" : "wb");
203 if (!f && (flags & NF_FATAL))
204 nasm_fatal(ERR_NOFILE, "unable to open output file: `%s': %s",
205 filename, strerror(errno));
207 return f;
211 * Report the existence of a file
213 bool nasm_file_exists(const char *filename)
215 #if defined(HAVE_FACCESSAT) && defined(AT_EACCESS)
216 return faccessat(AT_FDCWD, filename, R_OK, AT_EACCESS) == 0;
217 #elif defined(HAVE_ACCESS)
218 return access(filename, R_OK) == 0;
219 #else
220 FILE *f;
222 f = fopen(filename, "rb");
223 if (f) {
224 fclose(f);
225 return true;
226 } else {
227 return false;
229 #endif
233 * Report file size. This MAY move the file pointer.
235 off_t nasm_file_size(FILE *f)
237 #if defined(HAVE_FILENO) && defined(HAVE__FILELENGTHI64)
238 return _filelengthi64(fileno(f));
239 #elif defined(HAVE_FILENO) && defined(HAVE_FSTAT)
240 struct stat st;
242 if (fstat(fileno(f), &st))
243 return (off_t)-1;
245 return st.st_size;
246 #else
247 if (fseeko(f, 0, SEEK_END))
248 return (off_t)-1;
250 return ftello(f);
251 #endif
255 * Report file size given pathname
257 off_t nasm_file_size_by_path(const char *pathname)
259 #ifdef HAVE_STAT
260 struct stat st;
262 if (stat(pathname, &st))
263 return (off_t)-1;
265 return st.st_size;
266 #else
267 FILE *fp;
268 off_t len;
270 fp = nasm_open_read(pathname, NF_BINARY);
271 if (!fp)
272 return (off_t)-1;
274 len = nasm_file_size(fp);
275 fclose(fp);
277 return len;
278 #endif
282 * System page size
285 /* File scope since not all compilers like static data in inline functions */
286 static size_t nasm_pagemask;
288 static size_t get_pagemask(void)
290 size_t ps = 0;
292 # if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
293 ps = sysconf(_SC_PAGESIZE);
294 # elif defined(HAVE_GETPAGESIZE)
295 ps = getpagesize();
296 # endif
298 nasm_pagemask = ps = is_power2(ps) ? (ps - 1) : 0;
299 return ps;
302 static inline size_t pagemask(void)
304 size_t pm = nasm_pagemask;
306 if (unlikely(!pm))
307 return get_pagemask();
309 return pm;
313 * Try to map an input file into memory
315 const void *nasm_map_file(FILE *fp, off_t start, off_t len)
317 #if defined(HAVE_FILENO) && defined(HAVE_MMAP)
318 const char *p;
319 off_t astart; /* Aligned start */
320 size_t salign; /* Amount of start adjustment */
321 size_t alen; /* Aligned length */
322 const size_t page_mask = pagemask();
324 if (unlikely(!page_mask))
325 return NULL; /* Page size undefined? */
327 if (unlikely(!len))
328 return NULL; /* Mapping nothing... */
330 if (unlikely(len != (off_t)(size_t)len))
331 return NULL; /* Address space insufficient */
333 astart = start & ~(off_t)page_mask;
334 salign = start - astart;
335 alen = (len + salign + page_mask) & ~page_mask;
337 p = mmap(NULL, alen, PROT_READ, MAP_SHARED, fileno(fp), astart);
338 return unlikely(p == MAP_FAILED) ? NULL : p + salign;
339 #else
340 /* XXX: add Windows support? */
341 return NULL;
342 #endif
346 * Unmap an input file
348 void nasm_unmap_file(const void *p, size_t len)
350 #if defined(HAVE_FILENO) && defined(HAVE_MMAP)
351 const size_t page_mask = pagemask();
352 uintptr_t astart;
353 size_t salign;
354 size_t alen;
356 if (unlikely(!page_mask))
357 return;
359 astart = (uintptr_t)p & ~(uintptr_t)page_mask;
360 salign = (uintptr_t)p - astart;
361 alen = (len + salign + page_mask) & ~page_mask;
363 munmap((void *)astart, alen);
364 #endif