CBMC
Loading...
Searching...
No Matches
ld_mode.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: LD Mode
4
5Author: CM Wintersteiger, 2006
6
7\*******************************************************************/
8
11
12#include "ld_mode.h"
13
14#ifdef _WIN32
15#define EX_OK 0
16#define EX_USAGE 64
17#define EX_SOFTWARE 70
18#else
19#include <sysexits.h>
20#endif
21
22#include <util/cmdline.h>
23#include <util/config.h>
24#include <util/invariant.h>
25#include <util/run.h>
26
27#include "compile.h"
28#include "goto_cc_cmdline.h"
29#include "hybrid_binary.h"
30#include "linker_script_merge.h"
31
32#include <cstring>
33#include <filesystem>
34#include <fstream>
35#include <iostream>
36
37static std::string
38linker_name(const cmdlinet &cmdline, const std::string &base_name)
39{
40 if(cmdline.isset("native-linker"))
41 return cmdline.get_value("native-linker");
42
43 std::string::size_type pos = base_name.find("goto-ld");
44
45 if(
46 pos == std::string::npos || base_name == "goto-gcc" ||
47 base_name == "goto-ld")
48 return "ld";
49
50 std::string result = base_name;
51 result.replace(pos, 7, "ld");
52
53 return result;
54}
55
57 : goto_cc_modet(_cmdline, _base_name, gcc_message_handler),
58 goto_binary_tmp_suffix(".goto-cc-saved")
59{
60}
61
64{
66
67 // When --help is requested, just reproduce the output of the original
68 // compiler. This is so as not to confuse configure scripts that depend on
69 // particular information (such as the list of supported targets).
70 if(
71 cmdline.isset("help") || cmdline.isset("version") ||
72 cmdline.isset("print-sysroot"))
73 {
74 help();
75 return run_ld();
76 }
77
81 cmdline.isset("fatal-warnings") && !cmdline.isset("no-fatal-warnings"));
82
84 cmdline,
86 cmdline.isset("fatal-warnings") && !cmdline.isset("no-fatal-warnings"));
87
88 // determine actions to be undertaken
90
91 // model validation
92 compiler.validate_goto_model = cmdline.isset("validate-goto-model");
93
94 // get configuration
96
97 compiler.object_file_extension = "o";
98
99 if(cmdline.isset('L'))
100 compiler.library_paths = cmdline.get_values('L');
101 // Don't add the system paths!
102
103 if(cmdline.isset('l'))
104 compiler.libraries = cmdline.get_values('l');
105
106 if(cmdline.isset("static"))
107 compiler.libraries.push_back("c");
108
109 if(cmdline.isset('o'))
110 {
111 // given gcc -o file1 -o file2,
112 // gcc will output to file2, not file1
113 compiler.output_file_object = cmdline.get_values('o').back();
114 compiler.output_file_executable = cmdline.get_values('o').back();
115 }
116 else
117 {
118 compiler.output_file_object.clear();
119 compiler.output_file_executable = "a.out";
120 }
121
122 // We now iterate over any input files
123
124 for(const auto &arg : cmdline.parsed_argv)
125 if(arg.is_infile_name)
126 compiler.add_input_file(arg.arg);
127
128 // Revert to gcc in case there is no source to compile
129 // and no binary to link.
130
131 if(compiler.source_files.empty() && compiler.object_files.empty())
132 return run_ld(); // exit!
133
134 // do all the rest
135 if(compiler.doit())
136 return 1; // LD exit code for all kinds of errors
137
138 // We can generate hybrid ELF and Mach-O binaries
139 // containing both executable machine code and the goto-binary.
140 return ld_hybrid_binary(
142}
143
145{
147
148 // build new argv
149 std::vector<std::string> new_argv;
150 new_argv.reserve(cmdline.parsed_argv.size());
151 for(const auto &a : cmdline.parsed_argv)
152 new_argv.push_back(a.arg);
153
154 // overwrite argv[0]
156
158 log.debug() << "RUN:";
159 for(std::size_t i = 0; i < new_argv.size(); i++)
160 log.debug() << " " << new_argv[i];
161 log.debug() << messaget::eom;
162
163 return run(new_argv[0], new_argv, cmdline.stdin_file, "", "");
164}
165
168 const std::list<std::string> &object_files)
169{
170 std::string output_file;
171
172 if(cmdline.isset('o'))
173 {
175
176 if(output_file == "/dev/null")
177 return EX_OK;
178 }
179 else
180 output_file = "a.out";
181
183 log.debug() << "Running " << native_tool_name << " to generate hybrid binary"
184 << messaget::eom;
185
186 // save the goto-cc output file
187 std::string goto_binary = output_file + goto_binary_tmp_suffix;
188
189 try
190 {
191 std::filesystem::rename(output_file, goto_binary);
192 }
193 catch(const std::filesystem::filesystem_error &e)
194 {
195 log.error() << "Rename failed: " << e.what() << messaget::eom;
196 return 1;
197 }
198
199 const bool linking_efi = cmdline.get_value('m') == "i386pep";
200
201#ifdef __linux__
202 if(linking_efi)
203 {
204 const std::string objcopy_cmd = objcopy_command(native_tool_name);
205
206 for(const auto &object_file : object_files)
207 {
208 log.debug() << "stripping goto-cc sections before building EFI binary"
209 << messaget::eom;
210 // create a backup copy
211 const std::string bin_name = object_file + goto_binary_tmp_suffix;
212
213 std::ifstream in(object_file, std::ios::binary);
214 std::ofstream out(bin_name, std::ios::binary);
215 out << in.rdbuf();
216
217 // remove any existing goto-cc section
218 std::vector<std::string> objcopy_argv;
219
220 objcopy_argv.push_back(objcopy_cmd);
221 objcopy_argv.push_back("--remove-section=goto-cc");
222 objcopy_argv.push_back(object_file);
223
224 if(run(objcopy_argv[0], objcopy_argv) != 0)
225 {
226 log.debug() << "EFI binary preparation: removing goto-cc section failed"
227 << messaget::eom;
228 }
229 }
230 }
231#else
232 (void)object_files; // unused parameter
233#endif
234
235 int result = run_ld();
236
237 if(result == 0 && cmdline.isset('T'))
238 {
240 output_file, goto_binary, cmdline, message_handler);
241 result = ls_merge.add_linker_script_definitions();
242 }
243
244#ifdef __linux__
245 if(linking_efi)
246 {
247 log.debug() << "arch set with " << object_files.size() << messaget::eom;
248 for(const auto &object_file : object_files)
249 {
250 log.debug() << "EFI binary preparation: restoring object files"
251 << messaget::eom;
252 const std::string bin_name = object_file + goto_binary_tmp_suffix;
253 const int mv_result = rename(bin_name.c_str(), object_file.c_str());
254 if(mv_result != 0)
255 {
256 log.debug() << "Rename failed: " << std::strerror(errno)
257 << messaget::eom;
258 }
259 }
260 }
261#endif
262
263 if(result == 0)
264 {
266
267 result = hybrid_binary(
269 goto_binary,
274 }
275
276 return result;
277}
278
281{
282 std::cout << "goto-ld understands the options of "
283 << "ld plus the following.\n\n";
284}
configt config
Definition config.cpp:25
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
std::string get_value(char option) const
Definition cmdline.cpp:48
virtual bool isset(char option) const
Definition cmdline.cpp:30
const std::list< std::string > & get_values(const std::string &option) const
Definition cmdline.cpp:119
@ LINK_LIBRARY
Definition compile.h:41
@ COMPILE_LINK_EXECUTABLE
Definition compile.h:43
bool set(const cmdlinet &cmdline)
Definition config.cpp:863
void print_warnings_as_errors(bool yes)
With yes set to true, prefix warnings with "error:" instead of "warning:".
parsed_argvt parsed_argv
std::string stdin_file
goto_cc_cmdlinet & cmdline
message_handlert & message_handler
const std::string base_name
void help()
display command line help
void help_mode() final
display command line help
Definition ld_mode.cpp:280
const std::string goto_binary_tmp_suffix
Definition ld_mode.h:37
std::string native_tool_name
Definition ld_mode.h:35
gcc_message_handlert gcc_message_handler
Definition ld_mode.h:33
int run_ld()
call ld with original command line
Definition ld_mode.cpp:144
int doit() final
does it.
Definition ld_mode.cpp:63
ld_modet(goto_cc_cmdlinet &_cmdline, const std::string &_base_name)
Definition ld_mode.cpp:56
int ld_hybrid_binary(bool building_executable, const std::list< std::string > &object_files)
Build an ELF or Mach-O binary containing a goto-cc section.
Definition ld_mode.cpp:166
Synthesise definitions of symbols that are defined in linker scripts.
Class that provides messages with a built-in verbosity 'level'.
Definition message.h:154
static unsigned eval_verbosity(const std::string &user_input, const message_levelt default_verbosity, message_handlert &dest)
Parse a (user-)provided string as a verbosity level and set it as the verbosity of dest.
Definition message.cpp:105
@ M_ERROR
Definition message.h:169
static eomt eom
Definition message.h:289
Compile and link source and object files.
static std::string linker_name(const cmdlinet &cmdline, const std::string &base_name)
Definition gcc_mode.cpp:75
Command line interpretation for goto-cc.
int hybrid_binary(const std::string &compiler_or_linker, const std::string &goto_binary_file, const std::string &output_file, bool building_executable, message_handlert &message_handler, bool linking_efi)
Merges a goto binary into an object file (e.g.
std::string objcopy_command(const std::string &compiler_or_linker)
Return the name of the objcopy tool matching the chosen compiler or linker command.
Create hybrid binary with goto-binary section.
static std::string linker_name(const cmdlinet &cmdline, const std::string &base_name)
Definition ld_mode.cpp:38
Base class for command line interpretation.
Merge linker script-defined symbols into a goto-program.
literalt pos(literalt a)
Definition literal.h:194
double log(double x)
Definition math.c:2449
int run(const std::string &what, const std::vector< std::string > &argv)
Definition run.cpp:49
#define PRECONDITION(CONDITION)
Definition invariant.h:463