cprover
hybrid_binary.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Create hybrid binary with goto-binary section
4
5Author: 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
25std::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
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"
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)
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")
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}
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
mstreamt & error() const
Definition: message.h:399
mstreamt & debug() const
Definition: message.h:429
mstreamt & warning() const
Definition: message.h:404
static eomt eom
Definition: message.h:297
bool file_remove(const std::string &path)
C++17 will allow us to use std::filesystem::remove.
Definition: file_util.cpp:231
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.
unsigned int mode_t
Definition: kdev_t.h:12
int run(const std::string &what, const std::vector< std::string > &argv)
Definition: run.cpp:48
bool has_suffix(const std::string &s, const std::string &suffix)
Definition: suffix.h:17