CBMC
hybrid_binary.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Create hybrid binary with goto-binary section
4 
5 Author: Michael Tautschnig, 2018
6 
7 \*******************************************************************/
8 
11 
12 #include "hybrid_binary.h"
13 
14 #include <util/file_util.h>
15 #include <util/message.h>
16 #include <util/run.h>
17 #include <util/suffix.h>
18 
19 #include <cstring>
20 
21 #if defined(__APPLE__)
22 # include <sys/stat.h>
23 #endif
24 
25 std::string objcopy_command(const std::string &compiler_or_linker)
26 {
27  if(has_suffix(compiler_or_linker, "-ld"))
28  {
29  std::string objcopy_cmd = compiler_or_linker;
30  objcopy_cmd.erase(objcopy_cmd.size() - 2);
31  objcopy_cmd += "objcopy";
32 
33  return objcopy_cmd;
34  }
35  else
36  return "objcopy";
37 }
38 
40  const std::string &compiler_or_linker,
41  const std::string &goto_binary_file,
42  const std::string &output_file,
43  bool building_executable,
44  message_handlert &message_handler,
45  bool linking_efi)
46 {
47  messaget message(message_handler);
48 
49  int result = 0;
50 
51 #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
52  // we can use objcopy for both object files and executables
53  (void)building_executable;
54 
55  const std::string objcopy_cmd = objcopy_command(compiler_or_linker);
56 
57  // merge output from gcc or ld with goto-binary using objcopy
58 
59  message.debug() << "merging " << output_file << " and " << goto_binary_file
60  << " using " << objcopy_cmd
61  << messaget::eom;
62 
63  {
64  // Now add goto-binary as goto-cc section.
65  // Remove if it exists before, or otherwise adding fails.
66  std::vector<std::string> objcopy_argv = {
67  objcopy_cmd,
68  "--remove-section", "goto-cc",
69  "--add-section", "goto-cc=" + goto_binary_file, output_file};
70 
71  const int add_section_result = run(objcopy_argv[0], objcopy_argv);
72  if(add_section_result != 0)
73  {
74  if(linking_efi)
75  message.warning() << "cannot merge EFI binaries: goto-cc section lost"
76  << messaget::eom;
77  else
78  result = add_section_result;
79  }
80  }
81 
82  // delete the goto binary
83  bool remove_result = file_remove(goto_binary_file);
84  if(!remove_result)
85  {
86  message.error() << "Remove failed: " << std::strerror(errno)
87  << messaget::eom;
88  if(result == 0)
89  result = remove_result;
90  }
91 
92 #elif defined(__APPLE__)
93  // Mac
94 
95  message.debug() << "merging " << output_file << " and " << goto_binary_file
96  << " using " << (building_executable ? "lipo" : "ld")
97  << messaget::eom;
98 
99  if(building_executable)
100  {
101  // Add goto-binary as hppa7100LC section.
102  // This overwrites if there's already one.
103  std::vector<std::string> lipo_argv = {
104  "lipo", output_file, "-create", "-arch", "hppa7100LC", goto_binary_file,
105  "-output", output_file };
106 
107  result = run(lipo_argv[0], lipo_argv);
108 
109  if(result == 0)
110  {
111  // lipo creates an output file, but it does not set execute permissions,
112  // so the user is unable to directly execute the output file until its
113  // chmod +x
114  mode_t current_umask = umask(0);
115  umask(current_umask);
116  int chmod_result = chmod(
117  output_file.c_str(), (S_IRWXU | S_IRWXG | S_IRWXO) & ~current_umask);
118  if(chmod_result != 0)
119  {
120  message.error() << "Setting execute permissions failed: "
121  << std::strerror(errno) << messaget::eom;
122  result = chmod_result;
123  }
124  }
125  }
126  else
127  {
128  // This fails if there's already one.
129  std::vector<std::string> ld_argv = {"ld",
130  "-r",
131  "-sectcreate",
132  "__TEXT",
133  "goto-cc",
134  goto_binary_file,
135  output_file,
136  "-o",
137  output_file};
138 
139  result = run(ld_argv[0], ld_argv);
140  }
141 
142  // delete the goto binary
143  bool remove_result = file_remove(goto_binary_file);
144  if(!remove_result)
145  {
146  message.error() << "Remove failed: " << std::strerror(errno)
147  << messaget::eom;
148  if(result == 0)
149  result = remove_result;
150  }
151 
152 #else
153  // unused parameters
154  (void)compiler_or_linker;
155  (void)goto_binary_file;
156  (void)output_file;
157  (void)building_executable;
158  message.error() << "binary merging not implemented for this platform"
159  << messaget::eom;
160  result = 1;
161 #endif
162 
163  return result;
164 }
messaget
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:154
file_util.h
file_remove
bool file_remove(const std::string &path)
C++17 will allow us to use std::filesystem::remove.
Definition: file_util.cpp:231
run
int run(const std::string &what, const std::vector< std::string > &argv)
Definition: run.cpp:48
messaget::eom
static eomt eom
Definition: message.h:297
run.h
has_suffix
bool has_suffix(const std::string &s, const std::string &suffix)
Definition: suffix.h:17
messaget::error
mstreamt & error() const
Definition: message.h:399
objcopy_command
std::string objcopy_command(const std::string &compiler_or_linker)
Return the name of the objcopy tool matching the chosen compiler or linker command.
Definition: hybrid_binary.cpp:25
message_handlert
Definition: message.h:27
hybrid_binary.h
suffix.h
messaget::debug
mstreamt & debug() const
Definition: message.h:429
hybrid_binary
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.
Definition: hybrid_binary.cpp:39
message.h
messaget::warning
mstreamt & warning() const
Definition: message.h:404