blob: 1f1e63bca00c2c8e7972f615b26aa2371fe0b5b1 [file] [log] [blame]
H. Peter Anvinbdae10b2016-03-08 01:22:13 -08001/* ----------------------------------------------------------------------- *
2 *
H. Peter Anvincbd72b62017-02-23 18:19:25 -08003 * Copyright 1996-2017 The NASM Authors - All Rights Reserved
H. Peter Anvinbdae10b2016-03-08 01:22:13 -08004 * 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 Anvincbd72b62017-02-23 18:19:25 -080079/*
80 * On Win32, stat has a 32-bit file size but _stati64 has a 64-bit file
81 * size. However, as "stat" is already a macro, don't confuse the situation
82 * further by redefining it, instead we create our own.
83 */
H. Peter Anvin397c1692016-10-04 17:01:59 -070084#ifdef HAVE__STATI64
H. Peter Anvincbd72b62017-02-23 18:19:25 -080085# define nasm_stat _stati64
86#elif defined(HAVE_STAT)
87# define nasm_stat stat
88#endif
89
90#ifdef HAVE_FILENO
91# ifdef HAVE__FSTATI64
92# define nasm_fstat _fstati64
93# elif defined(HAVE_FSTAT)
94# define nasm_fstat fstat
95# endif
H. Peter Anvin397c1692016-10-04 17:01:59 -070096#endif
97
H. Peter Anvinbdae10b2016-03-08 01:22:13 -080098void nasm_write(const void *ptr, size_t size, FILE *f)
99{
100 size_t n = fwrite(ptr, 1, size, f);
101 if (n != size || ferror(f) || feof(f))
102 nasm_fatal(0, "unable to write output: %s", strerror(errno));
103}
104
105#ifdef WORDS_LITTLEENDIAN
106
107void fwriteint16_t(uint16_t data, FILE * fp)
108{
109 nasm_write(&data, 2, fp);
110}
111
112void fwriteint32_t(uint32_t data, FILE * fp)
113{
114 nasm_write(&data, 4, fp);
115}
116
117void fwriteint64_t(uint64_t data, FILE * fp)
118{
119 nasm_write(&data, 8, fp);
120}
121
122void fwriteaddr(uint64_t data, int size, FILE * fp)
123{
124 nasm_write(&data, size, fp);
125}
126
127#else /* not WORDS_LITTLEENDIAN */
128
129void fwriteint16_t(uint16_t data, FILE * fp)
130{
131 char buffer[2], *p = buffer;
132 WRITESHORT(p, data);
133 nasm_write(buffer, 2, fp);
134}
135
136void fwriteint32_t(uint32_t data, FILE * fp)
137{
138 char buffer[4], *p = buffer;
139 WRITELONG(p, data);
140 nasm_write(buffer, 4, fp);
141}
142
143void fwriteint64_t(uint64_t data, FILE * fp)
144{
145 char buffer[8], *p = buffer;
146 WRITEDLONG(p, data);
147 nasm_write(buffer, 8, fp);
148}
149
150void fwriteaddr(uint64_t data, int size, FILE * fp)
151{
152 char buffer[8], *p = buffer;
153 WRITEADDR(p, data, size);
154 nasm_write(buffer, size, fp);
155}
156
157#endif
158
159
H. Peter Anvind81a2352016-09-21 14:03:18 -0700160void fwritezero(off_t bytes, FILE *fp)
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800161{
162 size_t blksize;
163
164#ifdef nasm_ftruncate
165 if (bytes >= BUFSIZ && !ferror(fp) && !feof(fp)) {
166 off_t pos = ftello(fp);
167 if (pos >= 0) {
H. Peter Anvind81a2352016-09-21 14:03:18 -0700168 pos += bytes;
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800169 if (!fflush(fp) &&
H. Peter Anvind81a2352016-09-21 14:03:18 -0700170 !nasm_ftruncate(fileno(fp), pos) &&
171 !fseeko(fp, pos, SEEK_SET))
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800172 return;
173 }
174 }
175#endif
176
H. Peter Anvind81a2352016-09-21 14:03:18 -0700177 while (bytes > 0) {
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800178 blksize = (bytes < ZERO_BUF_SIZE) ? bytes : ZERO_BUF_SIZE;
179
180 nasm_write(zero_buffer, blksize, fp);
181 bytes -= blksize;
182 }
183}
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700184
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700185FILE *nasm_open_read(const char *filename, enum file_flags flags)
186{
187 FILE *f;
H. Peter Anvind81a2352016-09-21 14:03:18 -0700188 bool again = true;
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700189
H. Peter Anvind81a2352016-09-21 14:03:18 -0700190#ifdef __GLIBC__
191 /*
192 * Try to open this file with memory mapping for speed, unless we are
193 * going to do it "manually" with nasm_map_file()
194 */
195 if (!(flags & NF_FORMAP)) {
196 f = fopen(filename, (flags & NF_TEXT) ? "rtm" : "rbm");
197 again = (!f) && (errno == EINVAL); /* Not supported, try without m */
198 }
199#endif
200
201 if (again)
202 f = fopen(filename, (flags & NF_TEXT) ? "rt" : "rb");
203
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700204 if (!f && (flags & NF_FATAL))
205 nasm_fatal(ERR_NOFILE, "unable to open input file: `%s': %s",
206 filename, strerror(errno));
207
208 return f;
209}
210
211FILE *nasm_open_write(const char *filename, enum file_flags flags)
212{
213 FILE *f;
214
H. Peter Anvind81a2352016-09-21 14:03:18 -0700215 f = fopen(filename, (flags & NF_TEXT) ? "wt" : "wb");
216
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700217 if (!f && (flags & NF_FATAL))
218 nasm_fatal(ERR_NOFILE, "unable to open output file: `%s': %s",
219 filename, strerror(errno));
220
221 return f;
222}
H. Peter Anvinc1700892016-09-20 18:26:42 -0700223
H. Peter Anvind81a2352016-09-21 14:03:18 -0700224/*
225 * Report the existence of a file
226 */
227bool nasm_file_exists(const char *filename)
228{
229#if defined(HAVE_FACCESSAT) && defined(AT_EACCESS)
230 return faccessat(AT_FDCWD, filename, R_OK, AT_EACCESS) == 0;
231#elif defined(HAVE_ACCESS)
232 return access(filename, R_OK) == 0;
233#else
234 FILE *f;
235
236 f = fopen(filename, "rb");
237 if (f) {
238 fclose(f);
239 return true;
240 } else {
241 return false;
242 }
243#endif
244}
245
246/*
247 * Report file size. This MAY move the file pointer.
248 */
249off_t nasm_file_size(FILE *f)
250{
H. Peter Anvin397c1692016-10-04 17:01:59 -0700251#if defined(HAVE_FILENO) && defined(HAVE__FILELENGTHI64)
252 return _filelengthi64(fileno(f));
H. Peter Anvincbd72b62017-02-23 18:19:25 -0800253#elif defined(nasm_fstat)
254 struct nasm_stat st;
H. Peter Anvind81a2352016-09-21 14:03:18 -0700255
H. Peter Anvincbd72b62017-02-23 18:19:25 -0800256 if (nasm_fstat(fileno(f), &st))
H. Peter Anvind81a2352016-09-21 14:03:18 -0700257 return (off_t)-1;
258
259 return st.st_size;
260#else
261 if (fseeko(f, 0, SEEK_END))
262 return (off_t)-1;
263
264 return ftello(f);
265#endif
266}
267
268/*
269 * Report file size given pathname
270 */
271off_t nasm_file_size_by_path(const char *pathname)
272{
273#ifdef HAVE_STAT
274 struct stat st;
275
276 if (stat(pathname, &st))
277 return (off_t)-1;
278
279 return st.st_size;
280#else
281 FILE *fp;
282 off_t len;
283
284 fp = nasm_open_read(pathname, NF_BINARY);
285 if (!fp)
286 return (off_t)-1;
287
288 len = nasm_file_size(fp);
289 fclose(fp);
290
291 return len;
292#endif
293}
294
295/*
296 * System page size
H. Peter Anvincbd72b62017-02-23 18:19:25 -0800297 *
298 * Not needed unless we have mmap(), and can cause compile failures,
299 * e.g. on MinGW32, so we #if around it.
H. Peter Anvind81a2352016-09-21 14:03:18 -0700300 */
H. Peter Anvincbd72b62017-02-23 18:19:25 -0800301#if defined(HAVE_FILENO) && defined(HAVE_MMAP)
H. Peter Anvind81a2352016-09-21 14:03:18 -0700302
303/* File scope since not all compilers like static data in inline functions */
304static size_t nasm_pagemask;
305
306static size_t get_pagemask(void)
307{
308 size_t ps = 0;
309
310# if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
311 ps = sysconf(_SC_PAGESIZE);
312# elif defined(HAVE_GETPAGESIZE)
313 ps = getpagesize();
314# endif
315
316 nasm_pagemask = ps = is_power2(ps) ? (ps - 1) : 0;
317 return ps;
318}
319
320static inline size_t pagemask(void)
321{
322 size_t pm = nasm_pagemask;
323
324 if (unlikely(!pm))
325 return get_pagemask();
326
327 return pm;
328}
329
H. Peter Anvincbd72b62017-02-23 18:19:25 -0800330#endif
331
H. Peter Anvind81a2352016-09-21 14:03:18 -0700332/*
333 * Try to map an input file into memory
334 */
335const void *nasm_map_file(FILE *fp, off_t start, off_t len)
336{
337#if defined(HAVE_FILENO) && defined(HAVE_MMAP)
338 const char *p;
339 off_t astart; /* Aligned start */
340 size_t salign; /* Amount of start adjustment */
341 size_t alen; /* Aligned length */
342 const size_t page_mask = pagemask();
343
344 if (unlikely(!page_mask))
345 return NULL; /* Page size undefined? */
346
347 if (unlikely(!len))
348 return NULL; /* Mapping nothing... */
349
350 if (unlikely(len != (off_t)(size_t)len))
351 return NULL; /* Address space insufficient */
352
353 astart = start & ~(off_t)page_mask;
354 salign = start - astart;
355 alen = (len + salign + page_mask) & ~page_mask;
356
357 p = mmap(NULL, alen, PROT_READ, MAP_SHARED, fileno(fp), astart);
358 return unlikely(p == MAP_FAILED) ? NULL : p + salign;
359#else
360 /* XXX: add Windows support? */
H. Peter Anvincbd72b62017-02-23 18:19:25 -0800361 (void)fp; (void)start; (void)len;
H. Peter Anvind81a2352016-09-21 14:03:18 -0700362 return NULL;
363#endif
364}
365
366/*
367 * Unmap an input file
368 */
369void nasm_unmap_file(const void *p, size_t len)
370{
371#if defined(HAVE_FILENO) && defined(HAVE_MMAP)
372 const size_t page_mask = pagemask();
373 uintptr_t astart;
374 size_t salign;
375 size_t alen;
376
377 if (unlikely(!page_mask))
378 return;
379
380 astart = (uintptr_t)p & ~(uintptr_t)page_mask;
381 salign = (uintptr_t)p - astart;
382 alen = (len + salign + page_mask) & ~page_mask;
383
384 munmap((void *)astart, alen);
H. Peter Anvincbd72b62017-02-23 18:19:25 -0800385#else
386 (void)p; (void)len;
H. Peter Anvind81a2352016-09-21 14:03:18 -0700387#endif
388}