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/message.h>
15 #include <util/run.h>
16 #include <util/suffix.h>
17 
18 #include <cstring>
19 #include <filesystem>
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__) || \
52  defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
53  defined(__gnu_hurd__)
54  // we can use objcopy for both object files and executables
55  (void)building_executable;
56 
57  const std::string objcopy_cmd = objcopy_command(compiler_or_linker);
58 
59  // merge output from gcc or ld with goto-binary using objcopy
60 
61  message.debug() << "merging " << output_file << " and " << goto_binary_file
62  << " using " << objcopy_cmd
63  << messaget::eom;
64 
65  {
66  // Now add goto-binary as goto-cc section.
67  // Remove if it exists before, or otherwise adding fails.
68  std::vector<std::string> objcopy_argv = {
69  objcopy_cmd,
70  "--remove-section", "goto-cc",
71  "--add-section", "goto-cc=" + goto_binary_file, output_file};
72 
73  const int add_section_result = run(objcopy_argv[0], objcopy_argv);
74  if(add_section_result != 0)
75  {
76  if(linking_efi)
77  message.warning() << "cannot merge EFI binaries: goto-cc section lost"
78  << messaget::eom;
79  else
80  result = add_section_result;
81  }
82  }
83 
84  // delete the goto binary
85  bool remove_result = std::filesystem::remove(goto_binary_file);
86  if(!remove_result)
87  {
88  message.error() << "Remove failed: " << std::strerror(errno)
89  << messaget::eom;
90  if(result == 0)
91  result = remove_result;
92  }
93 
94 #elif defined(__APPLE__)
95  // Mac
96 
97  message.debug() << "merging " << output_file << " and " << goto_binary_file
98  << " using " << (building_executable ? "lipo" : "ld")
99  << messaget::eom;
100 
101  if(building_executable)
102  {
103  // Add goto-binary as hppa7100LC section.
104  // This overwrites if there's already one.
105  std::vector<std::string> lipo_argv = {
106  "lipo", output_file, "-create", "-arch", "hppa7100LC", goto_binary_file,
107  "-output", output_file };
108 
109  result = run(lipo_argv[0], lipo_argv);
110 
111  if(result == 0)
112  {
113  // lipo creates an output file, but it does not set execute permissions,
114  // so the user is unable to directly execute the output file until its
115  // chmod +x
116  mode_t current_umask = umask(0);
117  umask(current_umask);
118  int chmod_result = chmod(
119  output_file.c_str(), (S_IRWXU | S_IRWXG | S_IRWXO) & ~current_umask);
120  if(chmod_result != 0)
121  {
122  message.error() << "Setting execute permissions failed: "
123  << std::strerror(errno) << messaget::eom;
124  result = chmod_result;
125  }
126  }
127  }
128  else
129  {
130  // This fails if there's already one.
131  std::vector<std::string> ld_argv = {"ld",
132  "-r",
133  "-sectcreate",
134  "__TEXT",
135  "goto-cc",
136  goto_binary_file,
137  output_file,
138  "-o",
139  output_file};
140 
141  result = run(ld_argv[0], ld_argv);
142  }
143 
144  // delete the goto binary
145  bool remove_result = std::filesystem::remove(goto_binary_file);
146  if(!remove_result)
147  {
148  message.error() << "Remove failed: " << std::strerror(errno)
149  << messaget::eom;
150  if(result == 0)
151  result = remove_result;
152  }
153 
154 #else
155  // unused parameters
156  (void)compiler_or_linker;
157  (void)goto_binary_file;
158  (void)output_file;
159  (void)building_executable;
160  message.error() << "binary merging not implemented for this platform"
161  << messaget::eom;
162  result = 1;
163 #endif
164 
165  return result;
166 }
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
mstreamt & error() const
Definition: message.h:399
mstreamt & warning() const
Definition: message.h:404
mstreamt & debug() const
Definition: message.h:429
static eomt eom
Definition: message.h:297
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.
int run(const std::string &what, const std::vector< std::string > &argv)
Definition: run.cpp:48
char * strerror(int errnum)
Definition: string.c:1014
bool has_suffix(const std::string &s, const std::string &suffix)
Definition: suffix.h:17