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