blob: e525c83a0c5d04ed08de767c483994129664377d [file] [log] [blame]
H. Peter Anvinbdae10b2016-03-08 01:22:13 -08001/* ----------------------------------------------------------------------- *
2 *
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.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
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.
17 *
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.
31 *
32 * ----------------------------------------------------------------------- */
33
34#include "compiler.h"
35#include "nasmlib.h"
36
37#include <errno.h>
38
H. Peter Anvind81a2352016-09-21 14:03:18 -070039#ifdef HAVE_FCNTL_H
40# include <fcntl.h>
41#endif
42#ifdef HAVE_SYS_STAT_H
43# include <sys/stat.h>
44#endif
H. Peter Anvinbdae10b2016-03-08 01:22:13 -080045#ifdef HAVE_IO_H
46# include <io.h>
47#endif
48#ifdef HAVE_UNISTD_H
49# include <unistd.h>
50#endif
H. Peter Anvind81a2352016-09-21 14:03:18 -070051#ifdef HAVE_SYS_MMAN_H
52# include <sys/mman.h>
53#endif
H. Peter Anvinbdae10b2016-03-08 01:22:13 -080054
H. Peter Anvin397c1692016-10-04 17:01:59 -070055#if !defined(HAVE_FILENO) && defined(HAVE__FILENO)
56# define HAVE_FILENO 1
57# define fileno _fileno
58#endif
59
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
67
H. Peter Anvin7ab55952016-03-08 02:23:23 -080068/* Can we adjust the file size without actually writing all the bytes? */
69#ifdef HAVE_FILENO /* Useless without fileno() */
70# ifdef HAVE__CHSIZE_S
H. Peter Anvinc0aaf972016-05-10 15:18:00 -070071# define nasm_ftruncate(fd,size) _chsize_s(fd,size)
H. Peter Anvin7ab55952016-03-08 02:23:23 -080072# 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
78
H. Peter Anvin397c1692016-10-04 17:01:59 -070079#ifdef HAVE__STATI64
80# define HAVE_STAT 1
81# define stat _stati64
82#endif
83
H. Peter Anvinbdae10b2016-03-08 01:22:13 -080084void nasm_write(const void *ptr, size_t size, FILE *f)
85{
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));
89}
90
91#ifdef WORDS_LITTLEENDIAN
92
93void fwriteint16_t(uint16_t data, FILE * fp)
94{
95 nasm_write(&data, 2, fp);
96}
97
98void fwriteint32_t(uint32_t data, FILE * fp)
99{
100 nasm_write(&data, 4, fp);
101}
102
103void fwriteint64_t(uint64_t data, FILE * fp)
104{
105 nasm_write(&data, 8, fp);
106}
107
108void fwriteaddr(uint64_t data, int size, FILE * fp)
109{
110 nasm_write(&data, size, fp);
111}
112
113#else /* not WORDS_LITTLEENDIAN */
114
115void fwriteint16_t(uint16_t data, FILE * fp)
116{
117 char buffer[2], *p = buffer;
118 WRITESHORT(p, data);
119 nasm_write(buffer, 2, fp);
120}
121
122void fwriteint32_t(uint32_t data, FILE * fp)
123{
124 char buffer[4], *p = buffer;
125 WRITELONG(p, data);
126 nasm_write(buffer, 4, fp);
127}
128
129void fwriteint64_t(uint64_t data, FILE * fp)
130{
131 char buffer[8], *p = buffer;
132 WRITEDLONG(p, data);
133 nasm_write(buffer, 8, fp);
134}
135
136void fwriteaddr(uint64_t data, int size, FILE * fp)
137{
138 char buffer[8], *p = buffer;
139 WRITEADDR(p, data, size);
140 nasm_write(buffer, size, fp);
141}
142
143#endif
144
145
H. Peter Anvind81a2352016-09-21 14:03:18 -0700146void fwritezero(off_t bytes, FILE *fp)
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800147{
148 size_t blksize;
149
150#ifdef nasm_ftruncate
151 if (bytes >= BUFSIZ && !ferror(fp) && !feof(fp)) {
152 off_t pos = ftello(fp);
153 if (pos >= 0) {
H. Peter Anvind81a2352016-09-21 14:03:18 -0700154 pos += bytes;
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800155 if (!fflush(fp) &&
H. Peter Anvind81a2352016-09-21 14:03:18 -0700156 !nasm_ftruncate(fileno(fp), pos) &&
157 !fseeko(fp, pos, SEEK_SET))
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800158 return;
159 }
160 }
161#endif
162
H. Peter Anvind81a2352016-09-21 14:03:18 -0700163 while (bytes > 0) {
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800164 blksize = (bytes < ZERO_BUF_SIZE) ? bytes : ZERO_BUF_SIZE;
165
166 nasm_write(zero_buffer, blksize, fp);
167 bytes -= blksize;
168 }
169}
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700170
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700171FILE *nasm_open_read(const char *filename, enum file_flags flags)
172{
173 FILE *f;
H. Peter Anvind81a2352016-09-21 14:03:18 -0700174 bool again = true;
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700175
H. Peter Anvind81a2352016-09-21 14:03:18 -0700176#ifdef __GLIBC__
177 /*
178 * Try to open this file with memory mapping for speed, unless we are
179 * going to do it "manually" with nasm_map_file()
180 */
181 if (!(flags & NF_FORMAP)) {
182 f = fopen(filename, (flags & NF_TEXT) ? "rtm" : "rbm");
183 again = (!f) && (errno == EINVAL); /* Not supported, try without m */
184 }
185#endif
186
187 if (again)
188 f = fopen(filename, (flags & NF_TEXT) ? "rt" : "rb");
189
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700190 if (!f && (flags & NF_FATAL))
191 nasm_fatal(ERR_NOFILE, "unable to open input file: `%s': %s",
192 filename, strerror(errno));
193
194 return f;
195}
196
197FILE *nasm_open_write(const char *filename, enum file_flags flags)
198{
199 FILE *f;
200
H. Peter Anvind81a2352016-09-21 14:03:18 -0700201 f = fopen(filename, (flags & NF_TEXT) ? "wt" : "wb");
202
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700203 if (!f && (flags & NF_FATAL))
204 nasm_fatal(ERR_NOFILE, "unable to open output file: `%s': %s",
205 filename, strerror(errno));
206
207 return f;
208}
H. Peter Anvinc1700892016-09-20 18:26:42 -0700209
H. Peter Anvind81a2352016-09-21 14:03:18 -0700210/*
211 * Report the existence of a file
212 */
213bool nasm_file_exists(const char *filename)
214{
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;
221
222 f = fopen(filename, "rb");
223 if (f) {
224 fclose(f);
225 return true;
226 } else {
227 return false;
228 }
229#endif
230}
231
232/*
233 * Report file size. This MAY move the file pointer.
234 */
235off_t nasm_file_size(FILE *f)
236{
H. Peter Anvin397c1692016-10-04 17:01:59 -0700237#if defined(HAVE_FILENO) && defined(HAVE__FILELENGTHI64)
238 return _filelengthi64(fileno(f));
239#elif defined(HAVE_FILENO) && defined(HAVE_FSTAT)
H. Peter Anvind81a2352016-09-21 14:03:18 -0700240 struct stat st;
241
242 if (fstat(fileno(f), &st))
243 return (off_t)-1;
244
245 return st.st_size;
246#else
247 if (fseeko(f, 0, SEEK_END))
248 return (off_t)-1;
249
250 return ftello(f);
251#endif
252}
253
254/*
255 * Report file size given pathname
256 */
257off_t nasm_file_size_by_path(const char *pathname)
258{
259#ifdef HAVE_STAT
260 struct stat st;
261
262 if (stat(pathname, &st))
263 return (off_t)-1;
264
265 return st.st_size;
266#else
267 FILE *fp;
268 off_t len;
269
270 fp = nasm_open_read(pathname, NF_BINARY);
271 if (!fp)
272 return (off_t)-1;
273
274 len = nasm_file_size(fp);
275 fclose(fp);
276
277 return len;
278#endif
279}
280
281/*
282 * System page size
283 */
284
285/* File scope since not all compilers like static data in inline functions */
286static size_t nasm_pagemask;
287
288static size_t get_pagemask(void)
289{
290 size_t ps = 0;
291
292# if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
293 ps = sysconf(_SC_PAGESIZE);
294# elif defined(HAVE_GETPAGESIZE)
295 ps = getpagesize();
296# endif
297
298 nasm_pagemask = ps = is_power2(ps) ? (ps - 1) : 0;
299 return ps;
300}
301
302static inline size_t pagemask(void)
303{
304 size_t pm = nasm_pagemask;
305
306 if (unlikely(!pm))
307 return get_pagemask();
308
309 return pm;
310}
311
312/*
313 * Try to map an input file into memory
314 */
315const void *nasm_map_file(FILE *fp, off_t start, off_t len)
316{
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();
323
324 if (unlikely(!page_mask))
325 return NULL; /* Page size undefined? */
326
327 if (unlikely(!len))
328 return NULL; /* Mapping nothing... */
329
330 if (unlikely(len != (off_t)(size_t)len))
331 return NULL; /* Address space insufficient */
332
333 astart = start & ~(off_t)page_mask;
334 salign = start - astart;
335 alen = (len + salign + page_mask) & ~page_mask;
336
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
343}
344
345/*
346 * Unmap an input file
347 */
348void nasm_unmap_file(const void *p, size_t len)
349{
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;
355
356 if (unlikely(!page_mask))
357 return;
358
359 astart = (uintptr_t)p & ~(uintptr_t)page_mask;
360 salign = (uintptr_t)p - astart;
361 alen = (len + salign + page_mask) & ~page_mask;
362
363 munmap((void *)astart, alen);
364#endif
365}