asmcc 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/asmcc +4 -0
- data/lib/asmcc.rb +445 -0
- metadata +49 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9bb8677cf4a4a7825e28b603b32a032a75a805f6
|
4
|
+
data.tar.gz: b77f28755ad622294173b9a4fc50b0b3d2e8d2ff
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6871ff27f02b4ffdf139715951af599a85357e5cea46495285705bf8f7fe1946c9c80b0bb03c1ddd21275a6ce30929e54e7e50995806d24e4f5066d474a9a6dd
|
7
|
+
data.tar.gz: c0cc1fe622d6b82e6cc55dccd908d033702a5733dddf28c8b4f9bde083dfd47b7bbc7ca2ef915f685bb5d9f95b40d1dbed27d486c7518c2d2051fd2cb47d8334
|
data/bin/asmcc
ADDED
data/lib/asmcc.rb
ADDED
@@ -0,0 +1,445 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
CXX_TEMPLATE = <<-CODE_EOF
|
5
|
+
#include <cinttypes>
|
6
|
+
#include <cmath>
|
7
|
+
#include <cstddef>
|
8
|
+
#include <cstring>
|
9
|
+
#include <climits>
|
10
|
+
|
11
|
+
uint64_t factorial(uint64_t arg) {
|
12
|
+
if (arg <= 1) return 1;
|
13
|
+
return arg * factorial(arg - 1);
|
14
|
+
}
|
15
|
+
CODE_EOF
|
16
|
+
|
17
|
+
|
18
|
+
C_TEMPLATE = <<-CODE_EOF
|
19
|
+
#include <inttypes.h>
|
20
|
+
#include <math.h>
|
21
|
+
#include <stddef.h>
|
22
|
+
#include <string.h>
|
23
|
+
#include <limits.h>
|
24
|
+
#include <stdbool.h>
|
25
|
+
|
26
|
+
uint64_t factorial(uint64_t arg) {
|
27
|
+
if (arg <= 1) return 1;
|
28
|
+
return arg * factorial(arg - 1);
|
29
|
+
}
|
30
|
+
CODE_EOF
|
31
|
+
|
32
|
+
|
33
|
+
class AsmCC
|
34
|
+
def initialize
|
35
|
+
@parsed_settings = false
|
36
|
+
@custom_template = nil
|
37
|
+
@warnings = %W[all effc++]
|
38
|
+
@includes = %W[#{Dir.pwd} #{Dir.pwd}/include /usr/local/include]
|
39
|
+
@opt_level = '3'
|
40
|
+
|
41
|
+
@input = nil
|
42
|
+
@output = nil
|
43
|
+
|
44
|
+
@defines = []
|
45
|
+
@undefs = []
|
46
|
+
|
47
|
+
@enable_exns = false
|
48
|
+
@enable_rtti = false
|
49
|
+
|
50
|
+
@accurate_fp = true
|
51
|
+
|
52
|
+
@output = nil
|
53
|
+
|
54
|
+
@arch = 'native'
|
55
|
+
|
56
|
+
@xflags = []
|
57
|
+
|
58
|
+
@force_bits = nil
|
59
|
+
|
60
|
+
@verbose_asm = true
|
61
|
+
|
62
|
+
@edit_asm = false
|
63
|
+
@show_encoding = false
|
64
|
+
@debug = false
|
65
|
+
@demangle = true
|
66
|
+
@emit_llvm = false
|
67
|
+
|
68
|
+
@combined_output = false
|
69
|
+
|
70
|
+
@std = "c++1y"
|
71
|
+
@lang = :"c++"
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_settings!
|
75
|
+
return self if @parsed_settings
|
76
|
+
@parsed_settings = true
|
77
|
+
OptionParser.new do |opts|
|
78
|
+
opts.banner = 'Usage: asmcc [options]'
|
79
|
+
opts.separator ''
|
80
|
+
opts.separator 'Options:'
|
81
|
+
|
82
|
+
opts.on('-g', '--debug-info', 'Include debugging info?') do
|
83
|
+
@debug = true
|
84
|
+
end
|
85
|
+
|
86
|
+
opts.on('-O', '--opt-level 0123s', '01234s'.split(''), 'Set optimization level (3 by default).') do |v|
|
87
|
+
@opt_level = v
|
88
|
+
end
|
89
|
+
|
90
|
+
opts.on('-l', '--lang LANG', [:"c++", :c, :"objective-c", :"objective-c++"],
|
91
|
+
'Set language. Defaults to c++.',
|
92
|
+
' Must be one of ["c++", "c", "objective-c", "objective-c++"]') do |l|
|
93
|
+
@lang = l
|
94
|
+
end
|
95
|
+
|
96
|
+
opts.on('-s', '--std STD', String, 'Use the specified standard. Defaults to c++1y for c++/objc++, c11 for c/objc.') do |std|
|
97
|
+
@std = std
|
98
|
+
end
|
99
|
+
|
100
|
+
opts.on('-L', '--emit-llvm', 'Emit LLVM IR. (disables --show-encoding).') do |v|
|
101
|
+
@emit_llvm = true
|
102
|
+
end
|
103
|
+
|
104
|
+
opts.on('-F', '--[no-]fast-math', 'Prefer speed to accuracy for floating point? (off by default).') do |b|
|
105
|
+
@accurate_fp = !b
|
106
|
+
end
|
107
|
+
|
108
|
+
opts.on('-a', '--arch ARCH', String, 'Specify -march flag value (default is "native").') do |arch|
|
109
|
+
@arch = arch
|
110
|
+
end
|
111
|
+
|
112
|
+
opts.on('--m32', 'Force 32 bit compilation.') do
|
113
|
+
@force_bits = 32
|
114
|
+
end
|
115
|
+
|
116
|
+
opts.on('--m64', 'Force 64 bit compilation.') do
|
117
|
+
@force_bits = 64
|
118
|
+
end
|
119
|
+
|
120
|
+
opts.on('-X', '--Xcc f,l,a,g,s', Array, 'Pass extra flags to the compiler.') do |fs|
|
121
|
+
@xflags += fs
|
122
|
+
end
|
123
|
+
|
124
|
+
opts.on('-e', '--[no-]exceptions', 'Enable exceptions. Disabled by default.') do |e|
|
125
|
+
@enable_exns = e
|
126
|
+
end
|
127
|
+
|
128
|
+
opts.on('-r', '--[no-]rtti', 'Enable runtime type info. Disabled by default.') do |r|
|
129
|
+
@enable_rtti = r
|
130
|
+
end
|
131
|
+
|
132
|
+
opts.on('-E', '--edit-result', 'Open output file in editor.') do
|
133
|
+
@edit_asm = true
|
134
|
+
end
|
135
|
+
|
136
|
+
opts.on('--no-verbose-asm', 'Disable verbose assembly output.') do
|
137
|
+
@verbose_asm = false
|
138
|
+
end
|
139
|
+
|
140
|
+
opts.on('-D', '--define l,i,s,t', Array, 'Pass -Dl -Di -Ds -Dt to the compiler.') do |ds|
|
141
|
+
@defines += ds
|
142
|
+
end
|
143
|
+
|
144
|
+
opts.on('-U', '--undef l,i,s,t', Array, 'Pass -Ul -Ui -Us -Ut to the compiler (overrides -D).') do |us|
|
145
|
+
@undefs += us
|
146
|
+
end
|
147
|
+
|
148
|
+
opts.on('-W', '--warn w0,w1,etc', Array, 'Specify warnings to use (defaults to Wall,Wextra).') do |ws|
|
149
|
+
@warnings = ws
|
150
|
+
end
|
151
|
+
|
152
|
+
opts.on('-I', '--include d,i,r,s', Array, 'Extra -I include directories.',
|
153
|
+
' Automatically contains "`pwd`,`pwd`/include,/usr/local/include".') do |is|
|
154
|
+
@includes += is
|
155
|
+
end
|
156
|
+
|
157
|
+
opts.on('-S', '--show-encoding', 'Show encoding?') do
|
158
|
+
@show_encoding = true
|
159
|
+
end
|
160
|
+
|
161
|
+
opts.on('-C', '--combined-output', 'Output both the source fed into the compiler and the generated assembly') do
|
162
|
+
@combined_output = true
|
163
|
+
end
|
164
|
+
|
165
|
+
opts.on('-o', '--out FILE', 'Output to FILE instead of stdout.') do |f|
|
166
|
+
@output = f
|
167
|
+
end
|
168
|
+
|
169
|
+
opts.on('-i', '--input FILE', 'Use FILE as input instead of opening from the editor.') do |f|
|
170
|
+
if File.exist? f
|
171
|
+
@input = f
|
172
|
+
else
|
173
|
+
abort "No such file: \"#{f}\""
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
opts.on('-T', '--template FILE', String, 'Use FILE for template') do |f|
|
178
|
+
begin
|
179
|
+
@custom_template = IO.read(f)
|
180
|
+
rescue
|
181
|
+
puts "Warning: Unable to read template file: \"#{f}\", ignoring -T option..."
|
182
|
+
@custom_template = nil
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
opts.on('--[no-]demangle', 'Demangle C++ identifiers (requires `c++filt`, ignored for c and objc)') do |d|
|
187
|
+
@demangle = false
|
188
|
+
end
|
189
|
+
|
190
|
+
opts.on('-v', '--verbose', 'Pass -v to the compiler') do
|
191
|
+
@xflags << '-v'
|
192
|
+
end
|
193
|
+
|
194
|
+
opts.on('-h', '--help', 'Show this message') do
|
195
|
+
puts opts
|
196
|
+
exit
|
197
|
+
end
|
198
|
+
|
199
|
+
end.parse!
|
200
|
+
|
201
|
+
@show_encoding = false if @emit_llvm
|
202
|
+
|
203
|
+
unless is_cxx?
|
204
|
+
if @std.include? '++'
|
205
|
+
@std = @std.include?('gnu') ? 'gnu11' : 'c11'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
self
|
210
|
+
end
|
211
|
+
|
212
|
+
def try_again? prompt, default
|
213
|
+
print "#{prompt} #{default ? '[Y/n]' : '[y/N]'}:"
|
214
|
+
result = gets.strip
|
215
|
+
if result.empty?
|
216
|
+
default
|
217
|
+
elsif result[0] == 'Y' || result[0] == 'y'
|
218
|
+
true
|
219
|
+
elsif result[0] == 'N' || result[0] == 'n'
|
220
|
+
false
|
221
|
+
else
|
222
|
+
default
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def edit_file fpath
|
227
|
+
system(ENV['VISUAL'] || ENV['EDITOR'] || '/usr/bin/nano', fpath)
|
228
|
+
end
|
229
|
+
|
230
|
+
def is_darwin?
|
231
|
+
`uname`.strip == 'Darwin'
|
232
|
+
end
|
233
|
+
|
234
|
+
def is_cxx?
|
235
|
+
@lang == :"c++" or @lang == :"objective-c++"
|
236
|
+
end
|
237
|
+
|
238
|
+
def is_objc?
|
239
|
+
@lang == :"objective-c" or @lang == :"objective-c++"
|
240
|
+
end
|
241
|
+
|
242
|
+
def file_extension
|
243
|
+
case @lang
|
244
|
+
when :"c"
|
245
|
+
".c"
|
246
|
+
when :"c++"
|
247
|
+
".cpp"
|
248
|
+
when :"objective-c"
|
249
|
+
".m"
|
250
|
+
when :"objective-cpp"
|
251
|
+
".mm"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def stdlib_flag
|
256
|
+
if is_cxx?
|
257
|
+
is_darwin? ? '-stdlib=libc++' : '-stdlib=libstdc++'
|
258
|
+
else
|
259
|
+
''
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def exception_flag
|
264
|
+
if is_cxx?
|
265
|
+
if @enable_exns
|
266
|
+
"-fexceptions" + (is_objc? ? " -fobj-exceptions" : "")
|
267
|
+
else
|
268
|
+
"-fno-exceptions" + (is_objc? ? " -fno-objc-exceptions" : "")
|
269
|
+
end
|
270
|
+
else
|
271
|
+
''
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def rtti_flag
|
276
|
+
if is_cxx?
|
277
|
+
@enable_rtti ? '-frtti' : '-fno-rtti'
|
278
|
+
else
|
279
|
+
''
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def flags
|
284
|
+
%W[
|
285
|
+
-x#{@lang}
|
286
|
+
-march=#{@arch}
|
287
|
+
#{@force_bits.nil? ? '' : "-m#{@force_bits}"}
|
288
|
+
-S
|
289
|
+
#{@emit_llvm ? '-emit-llvm': ''}
|
290
|
+
#{@verbose_asm ? '-Xclang -masm-verbose' : ''}
|
291
|
+
|
292
|
+
-std=#{@std}
|
293
|
+
#{stdlib_flag}
|
294
|
+
-O#{@opt_level.strip}
|
295
|
+
|
296
|
+
#{exception_flag}
|
297
|
+
|
298
|
+
#{rtti_flag}
|
299
|
+
|
300
|
+
#{@accurate_fp ? '' : '-ffast-math'}
|
301
|
+
|
302
|
+
#{@warnings.map{|s| to_warning s}.join ' '}
|
303
|
+
#{@includes.map{|s| to_include s}.join ' '}
|
304
|
+
|
305
|
+
#{@defines.reject(&:empty?).map{|d|"-D#{d.strip}"}.join ' '}
|
306
|
+
#{@undefs.reject(&:empty?).map{|u|"-U#{d.strip}"}.join ' '}
|
307
|
+
|
308
|
+
#{@debug ? '-g' : ''}
|
309
|
+
#{@xflags.join ' '}
|
310
|
+
].reject(&:empty?)
|
311
|
+
end
|
312
|
+
|
313
|
+
def flag_str
|
314
|
+
flags.join ' '
|
315
|
+
end
|
316
|
+
|
317
|
+
def to_warning(s)
|
318
|
+
s.strip.sub /^(?:-?W)?/, "-W"
|
319
|
+
end
|
320
|
+
|
321
|
+
def to_include(s)
|
322
|
+
s.strip.sub /^(?:-I)?/, "-I"
|
323
|
+
end
|
324
|
+
|
325
|
+
def flags_summary
|
326
|
+
flags.reject{|f| /^-[WI]/ =~ f}.join ' '
|
327
|
+
end
|
328
|
+
|
329
|
+
def should_demangle
|
330
|
+
@demangle and is_cxx?()
|
331
|
+
end
|
332
|
+
|
333
|
+
def compiler_cmd path, summarize
|
334
|
+
command = "clang " + (summarize ? flags_summary : "#{flag_str} #{path} -o '-'")
|
335
|
+
command += " | clang -cc1as -show-encoding" if @show_encoding
|
336
|
+
command += " | c++filt" if should_demangle
|
337
|
+
end
|
338
|
+
|
339
|
+
def compiled_with comment_str
|
340
|
+
cmd = "clang #{flags_summary} "
|
341
|
+
cmd += " | clang -cc1as -show-encoding" if @show_encoding
|
342
|
+
cmd += " | c++filt" if should_demangle
|
343
|
+
"#{comment_str} Compiled with `#{cmd}`\n"
|
344
|
+
end
|
345
|
+
|
346
|
+
def invoke_compiler path
|
347
|
+
# this is getting pretty hacky
|
348
|
+
out = IO.popen("clang #{flag_str} #{path} -o '-'") do |pipe|
|
349
|
+
pipe.read
|
350
|
+
end
|
351
|
+
|
352
|
+
unless $?.exitstatus == 0
|
353
|
+
return [false]
|
354
|
+
end
|
355
|
+
|
356
|
+
if @show_encoding
|
357
|
+
out = IO.popen('clang -cc1as -show-encoding', 'r+') do |pipe|
|
358
|
+
pipe.write out
|
359
|
+
pipe.close_write
|
360
|
+
pipe.read
|
361
|
+
end
|
362
|
+
unless $?.exitstatus == 0
|
363
|
+
return [false]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
if should_demangle
|
368
|
+
out = IO.popen('c++filt', 'r+') do |pipe|
|
369
|
+
pipe.write out
|
370
|
+
pipe.close_write
|
371
|
+
pipe.read
|
372
|
+
end
|
373
|
+
unless $?.exitstatus == 0
|
374
|
+
return [false]
|
375
|
+
end
|
376
|
+
end
|
377
|
+
[true, out]
|
378
|
+
end
|
379
|
+
|
380
|
+
def template
|
381
|
+
if @custom_template
|
382
|
+
@custom_template
|
383
|
+
elsif is_cxx?
|
384
|
+
CXX_TEMPLATE
|
385
|
+
else
|
386
|
+
C_TEMPLATE
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
def run
|
391
|
+
parse_settings!
|
392
|
+
|
393
|
+
compiled = nil
|
394
|
+
file = nil
|
395
|
+
|
396
|
+
if @input.nil?
|
397
|
+
templ = template
|
398
|
+
else
|
399
|
+
templ = IO.read @input
|
400
|
+
end
|
401
|
+
|
402
|
+
file = Tempfile.new(['asmcc', file_extension])
|
403
|
+
|
404
|
+
path = file.path
|
405
|
+
|
406
|
+
file.print template
|
407
|
+
file.close()
|
408
|
+
|
409
|
+
compiled = nil
|
410
|
+
tried_once = false
|
411
|
+
|
412
|
+
while true
|
413
|
+
edit_file path if @input.nil? or tried_once
|
414
|
+
tried_once = true
|
415
|
+
result = invoke_compiler path
|
416
|
+
if result[0]
|
417
|
+
compiled = result[1]
|
418
|
+
break
|
419
|
+
elsif not try_again? "Compilation failed, try again?", true
|
420
|
+
exit(1)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
if @edit_asm or not @output.nil?
|
425
|
+
out_path = @output.nil? ? path : @output
|
426
|
+
File.open(out_path, 'w') { |f| output f, (IO.read path), compiled }
|
427
|
+
edit_file out_path if @edit_asm
|
428
|
+
else
|
429
|
+
output $stdout, (IO.read path), compiled
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
def output f, source, compiled
|
434
|
+
if @combined_output
|
435
|
+
f.puts source
|
436
|
+
f.puts "\n/******* Generated code *********/"
|
437
|
+
f.puts compiled_with "/*"
|
438
|
+
else
|
439
|
+
f.puts compiled_with @emit_llvm ? ';' : '#'
|
440
|
+
end
|
441
|
+
f.puts compiled.each_line.to_a.map{|line| "#{line.gsub(/([^\t]*)(\t)/) { $1 + " " * (8 - $1.length % 8) }}"}.join
|
442
|
+
f.puts "\n*/" if @combined_output
|
443
|
+
end
|
444
|
+
|
445
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asmcc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thom Chiovoloni
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: |
|
14
|
+
AsmCC is a command line tool to view the assembly or LLVM IR produced by
|
15
|
+
clang for a given file. It's essentially a command-line version of the
|
16
|
+
(now disabled) llvm online demo page.
|
17
|
+
email: chiovolonit@gmail.com
|
18
|
+
executables:
|
19
|
+
- asmcc
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- lib/asmcc.rb
|
24
|
+
- bin/asmcc
|
25
|
+
homepage: https://github.com/thomcc/asmcc
|
26
|
+
licenses:
|
27
|
+
- CC0
|
28
|
+
metadata: {}
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 2.0.3
|
46
|
+
signing_key:
|
47
|
+
specification_version: 4
|
48
|
+
summary: A script which painlessly compiles C/C++ to assembly.
|
49
|
+
test_files: []
|