-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.cc
156 lines (126 loc) · 4.06 KB
/
main.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "mold.h"
#include "config.h"
#include <cstring>
#include <filesystem>
#include <signal.h>
#include <tbb/global_control.h>
#ifdef USE_SYSTEM_MIMALLOC
#include <mimalloc-new-delete.h>
#endif
#ifdef __FreeBSD__
# include <sys/sysctl.h>
# include <unistd.h>
#endif
namespace mold {
std::string mold_version_string = MOLD_VERSION;
namespace elf {
int main(int argc, char **argv);
}
namespace macho {
int main(int argc, char **argv);
}
static std::string get_mold_version() {
if (mold_git_hash.empty())
return MOLD_PRODUCT_NAME " " MOLD_VERSION " (compatible with GNU ld)";
return MOLD_PRODUCT_NAME " " MOLD_VERSION " (" + mold_git_hash +
"; compatible with GNU ld)";
}
void cleanup() {
if (output_tmpfile)
unlink(output_tmpfile);
}
std::string errno_string() {
// strerror is not thread-safe, so guard it with a lock.
static std::mutex mu;
std::scoped_lock lock(mu);
return strerror(errno);
}
// Returns the path of the mold executable itself
std::string get_self_path() {
#ifdef __FreeBSD__
// /proc may not be mounted on FreeBSD. The proper way to get the
// current executable's path is to use sysctl(2).
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
size_t size;
sysctl(mib, 4, NULL, &size, NULL, 0);
std::string path;
path.resize(size);
sysctl(mib, 4, path.data(), &size, NULL, 0);
return path;
#else
return std::filesystem::read_symlink("/proc/self/exe").string();
#endif
}
// mold mmap's an output file, and the mmap succeeds even if there's
// no enough space left on the filesystem. The actual disk blocks are
// not allocated on the mmap call but when the program writes to it
// for the first time.
//
// If a disk becomes full as a result of a write to an mmap'ed memory
// region, the failure of the write is reported as a SIGBUS or structured
// exeption with code EXCEPTION_IN_PAGE_ERROR on Windows. This
// signal handler catches that signal and prints out a user-friendly
// error message. Without this, it is very hard to realize that the
// disk might be full.
#ifdef _WIN32
static LONG WINAPI vectored_handler(_EXCEPTION_POINTERS *exception_info) {
static std::mutex mu;
std::scoped_lock lock{mu};
PEXCEPTION_RECORD exception_record = exception_info->ExceptionRecord;
ULONG_PTR *exception_information = exception_record->ExceptionInformation;
if (exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR &&
(ULONG_PTR)output_buffer_start <= exception_information[1] &&
exception_information[1] < (ULONG_PTR)output_buffer_end) {
const char msg[] =
MOLD_PRODUCT_NAME ": failed to write to an output file. Disk full?\n";
(void)!write(_fileno(stderr), msg, sizeof(msg) - 1);
}
cleanup();
_exit(1);
}
void install_signal_handler() {
AddVectoredExceptionHandler(0, vectored_handler);
}
#else
static void sighandler(int signo, siginfo_t *info, void *ucontext) {
static std::mutex mu;
std::scoped_lock lock{mu};
if ((signo == SIGSEGV || signo == SIGBUS) &&
output_buffer_start <= info->si_addr &&
info->si_addr < output_buffer_end) {
const char msg[] =
MOLD_PRODUCT_NAME ": failed to write to an output file. Disk full?\n";
(void)!write(STDERR_FILENO, msg, sizeof(msg) - 1);
}
cleanup();
_exit(1);
}
void install_signal_handler() {
struct sigaction action;
action.sa_sigaction = sighandler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
sigaction(SIGBUS, &action, NULL);
}
#endif
i64 get_default_thread_count() {
// mold doesn't scale well above 32 threads.
int n = tbb::global_control::active_value(
tbb::global_control::max_allowed_parallelism);
return std::min(n, 32);
}
} // namespace mold
int main(int argc, char **argv) {
mold::mold_version = mold::get_mold_version();
mold::mold_product_name = MOLD_PRODUCT_NAME;
std::string cmd = mold::filepath(argv[0]).filename().string();
if (cmd == "ld64" || cmd == "ld64.mold")
return mold::macho::main(argc, argv);
return mold::elf::main(argc, argv);
}