CBMC
ld_mode.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: LD Mode
4 
5 Author: 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 
37 static std::string
38 linker_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 
56 ld_modet::ld_modet(goto_cc_cmdlinet &_cmdline, const std::string &_base_name)
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 
83  compilet compiler(
84  cmdline,
86  cmdline.isset("fatal-warnings") && !cmdline.isset("no-fatal-warnings"));
87 
88  // determine actions to be undertaken
89  compiler.mode = compilet::LINK_LIBRARY;
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(
141  compiler.mode == compilet::COMPILE_LINK_EXECUTABLE, compiler.object_files);
142 }
143 
145 {
146  PRECONDITION(!cmdline.parsed_argv.empty());
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]
155  new_argv[0] = native_tool_name;
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 
167  bool building_executable,
168  const std::list<std::string> &object_files)
169 {
170  std::string output_file;
171 
172  if(cmdline.isset('o'))
173  {
174  output_file = cmdline.get_value('o');
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  {
239  linker_script_merget ls_merge(
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  {
265  std::string native_linker = linker_name(cmdline, base_name);
266 
267  result = hybrid_binary(
268  native_linker,
269  goto_binary,
270  output_file,
271  building_executable,
273  linking_efi);
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
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:109
@ LINK_LIBRARY
Definition: compile.h:41
@ COMPILE_LINK_EXECUTABLE
Definition: compile.h:43
std::string output_file_object
Definition: compile.h:55
bool add_input_file(const std::string &)
puts input file names into a list and does preprocessing for libraries.
Definition: compile.cpp:167
std::list< std::string > libraries
Definition: compile.h:49
std::list< std::string > object_files
Definition: compile.h:48
bool doit()
reads and source and object files, compiles and links them into goto program objects.
Definition: compile.cpp:54
std::list< std::string > source_files
Definition: compile.h:47
std::string object_file_extension
Definition: compile.h:51
bool validate_goto_model
Definition: compile.h:36
enum compilet::@3 mode
std::list< std::string > library_paths
Definition: compile.h:46
std::string output_file_executable
Definition: compile.h:52
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
Definition: goto_cc_mode.h:38
message_handlert & message_handler
Definition: goto_cc_mode.h:40
const std::string base_name
Definition: goto_cc_mode.h:39
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.
int add_linker_script_definitions()
Add values of linkerscript-defined symbols to the goto-binary.
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.
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 binary(const constant_exprt &src)
Definition: json_expr.cpp:187
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:2776
int run(const std::string &what, const std::vector< std::string > &argv)
Definition: run.cpp:48
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
char * strerror(int errnum)
Definition: string.c:1014
#define size_type
Definition: unistd.c:347