patchelf 1.5.2 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +17 -5
- data/lib/patchelf/alt_saver.rb +94 -76
- data/lib/patchelf/cli.rb +1 -1
- data/lib/patchelf/patcher.rb +1 -1
- data/lib/patchelf/saver.rb +1 -1
- data/lib/patchelf/version.rb +1 -1
- metadata +22 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 64cae3b6070bf26b6716a82886fcb183f20213bf0c396501141e93c1e7951ffa
|
|
4
|
+
data.tar.gz: 49793e2b2bf154c0d4ff70f1533130495a0161db418248fc39105997159c59c8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d6b6dc9f7caa90f2abe18013a778e4ede2206f848e377e3cfce635b83ffc75b4dbc66c9b318899040bffa9553e8f0820cab95f92af445adc783efbbe47e0395f
|
|
7
|
+
data.tar.gz: b9566cc7487e8225e07f5ea7a29698e1d280969fde9f93ef0c0b1cd08d11595e92243883ed6123ef3918c1776003939c16a49d89aed6fc5da7a685e92a4a6a5a
|
data/README.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
[](https://rubygems.org/gems/patchelf)
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/patchelf)
|
|
4
|
-
[](http://choosealicense.com/licenses/mit/)
|
|
4
|
+
[](https://github.com/Homebrew/patchelf.rb/actions/workflows/tests.yml)
|
|
5
|
+
[](https://codecov.io/gh/Homebrew/patchelf.rb)
|
|
6
|
+
[](https://www.rubydoc.info/gems/patchelf)
|
|
7
|
+
[](https://choosealicense.com/licenses/mit/)
|
|
9
8
|
|
|
10
9
|
# patchelf.rb
|
|
11
10
|
|
|
@@ -136,3 +135,16 @@ patcher.save('ls.patch')
|
|
|
136
135
|
## Environment
|
|
137
136
|
|
|
138
137
|
patchelf.rb is implemented in pure Ruby, so it should work in all environments include Linux, macOS, and Windows!
|
|
138
|
+
|
|
139
|
+
## Project Authors
|
|
140
|
+
|
|
141
|
+
The git history remains the definitive record of all contributions.
|
|
142
|
+
|
|
143
|
+
### Original Author and Project Founder
|
|
144
|
+
|
|
145
|
+
* david942j (@david942j)
|
|
146
|
+
|
|
147
|
+
### Maintainers
|
|
148
|
+
|
|
149
|
+
* Homebrew maintainers
|
|
150
|
+
* david942j (@david942j)
|
data/lib/patchelf/alt_saver.rb
CHANGED
|
@@ -58,7 +58,7 @@ module PatchELF
|
|
|
58
58
|
@out_file = out_file
|
|
59
59
|
@set = set
|
|
60
60
|
|
|
61
|
-
f = File.open(in_file, 'rb')
|
|
61
|
+
f = File.open(in_file, 'rb') # rubocop:disable Style/FileOpen
|
|
62
62
|
# the +@buffer+ and +@elf+ both could work on same +StringIO+ stream,
|
|
63
63
|
# the updating of @buffer in place blocks us from looking up old values.
|
|
64
64
|
# TODO: cache the values needed later, use same stream for +@buffer+ and +@elf+.
|
|
@@ -130,14 +130,12 @@ module PatchELF
|
|
|
130
130
|
find_section '.dynstr'
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
-
#
|
|
133
|
+
# Yields dynamic tag, and its offset in @buffer.
|
|
134
|
+
# @yieldparam [ELFTools::Structs::ELF_Dyn] dyn
|
|
135
|
+
# @yieldparam [Integer] offset The offset of this dynamic tag within +@buffer+.
|
|
134
136
|
def each_dynamic_tags
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
sec = find_section '.dynamic'
|
|
138
|
-
return unless sec
|
|
139
|
-
|
|
140
|
-
return if sec.header.sh_type == ELFTools::Constants::SHT_NOBITS
|
|
137
|
+
sec = find_section('.dynamic')
|
|
138
|
+
return if sec.nil? || sec.header.sh_type == ELFTools::Constants::SHT_NOBITS
|
|
141
139
|
|
|
142
140
|
shdr = sec.header
|
|
143
141
|
with_buf_at(shdr.sh_offset) do |buf|
|
|
@@ -149,8 +147,8 @@ module PatchELF
|
|
|
149
147
|
break if dyn.d_tag == ELFTools::Constants::DT_NULL
|
|
150
148
|
|
|
151
149
|
yield dyn, buf_dyn_offset
|
|
152
|
-
#
|
|
153
|
-
buf.seek
|
|
150
|
+
# It's possible the caller may modify @buffer.pos, seek to ensure it points to the next tag.
|
|
151
|
+
buf.seek(buf_dyn_offset + dyn.num_bytes)
|
|
154
152
|
end
|
|
155
153
|
end
|
|
156
154
|
end
|
|
@@ -675,18 +673,13 @@ module PatchELF
|
|
|
675
673
|
new_phdrs = []
|
|
676
674
|
|
|
677
675
|
while curr_off < end_off
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
next if sec.type != ELFTools::Constants::SHT_NOTE
|
|
681
|
-
|
|
682
|
-
size = sec.header.sh_size.to_i
|
|
683
|
-
curr_off = sec.header.sh_offset.to_i
|
|
684
|
-
break
|
|
685
|
-
end
|
|
676
|
+
section = sections_at_aligned_offset(curr_off).find { |sec| sec.type == ELFTools::Constants::SHT_NOTE }
|
|
677
|
+
raise PatchError, 'cannot normalize PT_NOTE segment: non-contiguous SHT_NOTE sections' if section.nil?
|
|
686
678
|
|
|
687
|
-
|
|
679
|
+
size = section.header.sh_size.to_i
|
|
680
|
+
curr_off = section.header.sh_offset.to_i
|
|
688
681
|
|
|
689
|
-
if curr_off + size > end_off
|
|
682
|
+
if size.zero? || curr_off + size > end_off
|
|
690
683
|
raise PatchError, 'cannot normalize PT_NOTE segment: partially mapped SHT_NOTE section'
|
|
691
684
|
end
|
|
692
685
|
|
|
@@ -710,6 +703,8 @@ module PatchELF
|
|
|
710
703
|
end
|
|
711
704
|
|
|
712
705
|
def sections_at_aligned_offset(offset)
|
|
706
|
+
return to_enum(__method__, offset) unless block_given?
|
|
707
|
+
|
|
713
708
|
@sections.each do |sec|
|
|
714
709
|
shdr = sec.header
|
|
715
710
|
|
|
@@ -743,7 +738,6 @@ module PatchELF
|
|
|
743
738
|
phdr.p_vaddr -= shift if phdr.p_vaddr > shift
|
|
744
739
|
end
|
|
745
740
|
|
|
746
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
|
747
741
|
def shift_segments(shift, start_offset)
|
|
748
742
|
split_index = -1
|
|
749
743
|
split_shift = 0
|
|
@@ -752,9 +746,8 @@ module PatchELF
|
|
|
752
746
|
phdr = seg.header
|
|
753
747
|
p_start = phdr.p_offset
|
|
754
748
|
|
|
755
|
-
if p_start
|
|
756
|
-
|
|
757
|
-
raise PatchError, "split_index(#{split_index}) != -1" if split_index != -1
|
|
749
|
+
if (p_start...(p_start + phdr.p_filesz)).cover?(start_offset) && phdr.p_type == ELFTools::Constants::PT_LOAD
|
|
750
|
+
raise PatchError, 'PT_LOAD segments overlapped, unable to shift segments' if split_index != -1
|
|
758
751
|
|
|
759
752
|
split_index = idx
|
|
760
753
|
split_shift = start_offset - p_start
|
|
@@ -775,11 +768,10 @@ module PatchELF
|
|
|
775
768
|
end
|
|
776
769
|
end
|
|
777
770
|
|
|
778
|
-
raise PatchError, "
|
|
771
|
+
raise PatchError, "No PT_LOAD found covers offset 0x#{start_offset.to_s(16)}" if split_index == -1
|
|
779
772
|
|
|
780
773
|
[split_index, split_shift]
|
|
781
774
|
end
|
|
782
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
|
783
775
|
|
|
784
776
|
def shift_file(extra_pages, start_offset, extra_bytes)
|
|
785
777
|
raise PatchError, "start_offset(#{start_offset}) < ehdr.num_bytes" if start_offset < ehdr.num_bytes
|
|
@@ -865,9 +857,9 @@ module PatchELF
|
|
|
865
857
|
sec_name
|
|
866
858
|
end
|
|
867
859
|
|
|
868
|
-
#
|
|
869
|
-
#
|
|
870
|
-
#
|
|
860
|
+
# Given a +dyn.d_tag+, returns the section name it must be synced to.
|
|
861
|
+
# Returns +nil+ when given tag maps to no section, or when its okay to skip if section is not found.
|
|
862
|
+
# @return [String?]
|
|
871
863
|
def dyn_tag_to_section_name(d_tag)
|
|
872
864
|
case d_tag
|
|
873
865
|
when ELFTools::Constants::DT_STRTAB, ELFTools::Constants::DT_STRSZ
|
|
@@ -901,32 +893,37 @@ module PatchELF
|
|
|
901
893
|
end
|
|
902
894
|
end
|
|
903
895
|
|
|
896
|
+
# @return [ELFTools::Structs::ELF_Shdr?]
|
|
897
|
+
def dyn_tag_to_shdr(d_tag)
|
|
898
|
+
sec_name = dyn_tag_to_section_name(d_tag)
|
|
899
|
+
return if sec_name.nil?
|
|
900
|
+
|
|
901
|
+
find_section(sec_name)&.header
|
|
902
|
+
end
|
|
903
|
+
|
|
904
904
|
# updates dyn tags by syncing it with @section values
|
|
905
905
|
def sync_dyn_tags!
|
|
906
|
+
# Position of the fist dynamic tag.
|
|
906
907
|
dyn_table_offset = nil
|
|
907
908
|
each_dynamic_tags do |dyn, buf_off|
|
|
908
909
|
dyn_table_offset ||= buf_off
|
|
909
910
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
end
|
|
911
|
+
if dyn.d_tag == ELFTools::Constants::DT_MIPS_RLD_MAP_REL
|
|
912
|
+
rld_map = find_section('.rld_map')
|
|
913
|
+
dyn.d_val = if rld_map
|
|
914
|
+
rld_map.header.sh_addr.to_i - (buf_off - dyn_table_offset) -
|
|
915
|
+
find_section('.dynamic').header.sh_addr.to_i
|
|
916
|
+
else
|
|
917
|
+
Logger.warn 'DT_MIPS_RLD_MAP_REL entry is present, but .rld_map section is not'
|
|
918
|
+
0
|
|
919
|
+
end
|
|
920
|
+
else
|
|
921
|
+
shdr = dyn_tag_to_shdr(dyn.d_tag)
|
|
922
|
+
next if shdr.nil?
|
|
923
923
|
|
|
924
|
-
|
|
924
|
+
dyn.d_val = dyn.d_tag == ELFTools::Constants::DT_STRSZ ? shdr.sh_size.to_i : shdr.sh_addr.to_i
|
|
925
925
|
end
|
|
926
926
|
|
|
927
|
-
shdr = find_section(sec_name).header
|
|
928
|
-
dyn.d_val = dyn.d_tag == ELFTools::Constants::DT_STRSZ ? shdr.sh_size.to_i : shdr.sh_addr.to_i
|
|
929
|
-
|
|
930
927
|
with_buf_at(buf_off) { |wbuf| dyn.write(wbuf) }
|
|
931
928
|
end
|
|
932
929
|
end
|
|
@@ -945,6 +942,8 @@ module PatchELF
|
|
|
945
942
|
nil
|
|
946
943
|
end
|
|
947
944
|
|
|
945
|
+
# Some sections have their corresponding segment.
|
|
946
|
+
# Use this utility when a section is being patched so its segment should be updated with the same values.
|
|
948
947
|
def sync_sec_to_seg(shdr, phdr)
|
|
949
948
|
phdr.p_offset = shdr.sh_offset.to_i
|
|
950
949
|
phdr.p_vaddr = phdr.p_paddr = shdr.sh_addr.to_i
|
|
@@ -962,6 +961,8 @@ module PatchELF
|
|
|
962
961
|
end
|
|
963
962
|
|
|
964
963
|
# Returns a blank shdr if the section doesn't exist.
|
|
964
|
+
#
|
|
965
|
+
# @return [ELFTools::Structs::ELF_Shdr]
|
|
965
966
|
def find_or_create_section_header(rsec_name)
|
|
966
967
|
shdr = find_section(rsec_name)&.header
|
|
967
968
|
shdr ||= ELFTools::Structs::ELF_Shdr.new(endian: endian, elf_class: elf_class)
|
|
@@ -991,11 +992,54 @@ module PatchELF
|
|
|
991
992
|
(s_start >= p_start && s_start < p_end) || (s_end > p_start && s_end <= p_end)
|
|
992
993
|
end
|
|
993
994
|
|
|
995
|
+
# Used when patching sections.
|
|
996
|
+
# For sections with a correspondence segment, update the segment values.
|
|
997
|
+
# @return [void]
|
|
998
|
+
def section_sync_correspondence_segment(sec_name, shdr)
|
|
999
|
+
seg_type = {
|
|
1000
|
+
'.interp' => ELFTools::Constants::PT_INTERP,
|
|
1001
|
+
'.dynamic' => ELFTools::Constants::PT_DYNAMIC,
|
|
1002
|
+
'.MIPS.abiflags' => ELFTools::Constants::PT_MIPS_ABIFLAGS,
|
|
1003
|
+
'.note.gnu.property' => ELFTools::Constants::PT_GNU_PROPERTY
|
|
1004
|
+
}[sec_name]
|
|
1005
|
+
return if seg_type.nil?
|
|
1006
|
+
|
|
1007
|
+
phdrs_by_type(seg_type) { |phdr| sync_sec_to_seg(shdr, phdr) }
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
# Similar to +section_sync_correspondence_segment+ but dedicate for note sections as it is allowed to have multiple
|
|
1011
|
+
# note segments.
|
|
1012
|
+
# This function searches all note segments and only sync the one matched with the section values before patching.
|
|
1013
|
+
#
|
|
1014
|
+
# NOTE: This function is no-op if +shdr+ does not have section type +ELFTools::Constants::SHT_NOTE+.
|
|
1015
|
+
#
|
|
1016
|
+
# @param [Integer] orig_sh_offset The original section offset value.
|
|
1017
|
+
# @param [Integer] orig_sh_size The original section size value.
|
|
1018
|
+
# @param [ELFTools::Structs::ELF_Shdr] shdr The section header with values after patched.
|
|
1019
|
+
#
|
|
1020
|
+
# @return [void]
|
|
1021
|
+
def sync_note_segment(orig_sh_offset, orig_sh_size, shdr)
|
|
1022
|
+
return if shdr.sh_type != ELFTools::Constants::SHT_NOTE
|
|
1023
|
+
|
|
1024
|
+
phdrs_by_type(ELFTools::Constants::PT_NOTE) do |phdr|
|
|
1025
|
+
s_start = orig_sh_offset
|
|
1026
|
+
s_end = s_start + orig_sh_size
|
|
1027
|
+
p_start = phdr.p_offset
|
|
1028
|
+
p_end = p_start + phdr.p_filesz
|
|
1029
|
+
|
|
1030
|
+
# Skip if no overlap.
|
|
1031
|
+
next unless section_bounds_within_segment?(s_start, s_end, p_start, p_end)
|
|
1032
|
+
|
|
1033
|
+
# Only support exact matches.
|
|
1034
|
+
raise PatchError, 'unsupported overlap of SHT_NOTE and PT_NOTE' unless [p_start, p_end] == [s_start, s_end]
|
|
1035
|
+
|
|
1036
|
+
sync_sec_to_seg(shdr, phdr)
|
|
1037
|
+
end
|
|
1038
|
+
end
|
|
1039
|
+
|
|
994
1040
|
def write_replaced_sections(cur_off, start_addr, start_offset)
|
|
995
1041
|
overwrite_replaced_sections
|
|
996
1042
|
|
|
997
|
-
noted_phdrs = Set.new
|
|
998
|
-
|
|
999
1043
|
# the sort is necessary, the strategy in ruby and Cpp to iterate map/hash
|
|
1000
1044
|
# is different, patchelf v0.10 iterates the replaced_sections sorted by
|
|
1001
1045
|
# keys.
|
|
@@ -1018,34 +1062,8 @@ module PatchELF
|
|
|
1018
1062
|
shdr.sh_size = rsec_data.size
|
|
1019
1063
|
|
|
1020
1064
|
write_section_alignment(shdr)
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
'.interp' => ELFTools::Constants::PT_INTERP,
|
|
1024
|
-
'.dynamic' => ELFTools::Constants::PT_DYNAMIC,
|
|
1025
|
-
'.MIPS.abiflags' => ELFTools::Constants::PT_MIPS_ABIFLAGS,
|
|
1026
|
-
'.note.gnu.property' => ELFTools::Constants::PT_GNU_PROPERTY
|
|
1027
|
-
}[rsec_name]
|
|
1028
|
-
|
|
1029
|
-
phdrs_by_type(seg_type) { |phdr| sync_sec_to_seg(shdr, phdr) }
|
|
1030
|
-
|
|
1031
|
-
if shdr.sh_type == ELFTools::Constants::SHT_NOTE
|
|
1032
|
-
phdrs_by_type(ELFTools::Constants::PT_NOTE) do |phdr, idx|
|
|
1033
|
-
next if noted_phdrs.include?(idx)
|
|
1034
|
-
|
|
1035
|
-
s_start = orig_sh_offset
|
|
1036
|
-
s_end = s_start + orig_sh_size
|
|
1037
|
-
p_start = phdr.p_offset
|
|
1038
|
-
p_end = p_start + phdr.p_filesz
|
|
1039
|
-
|
|
1040
|
-
next unless section_bounds_within_segment?(s_start, s_end, p_start, p_end)
|
|
1041
|
-
|
|
1042
|
-
raise PatchError, 'unsupported overlap of SHT_NOTE and PT_NOTE' if p_start != s_start || p_end != s_end
|
|
1043
|
-
|
|
1044
|
-
sync_sec_to_seg(shdr, phdr)
|
|
1045
|
-
|
|
1046
|
-
noted_phdrs << idx
|
|
1047
|
-
end
|
|
1048
|
-
end
|
|
1065
|
+
section_sync_correspondence_segment(rsec_name, shdr)
|
|
1066
|
+
sync_note_segment(orig_sh_offset, orig_sh_size, shdr)
|
|
1049
1067
|
|
|
1050
1068
|
cur_off += Helper.alignup(rsec_data.size, @section_alignment)
|
|
1051
1069
|
end
|
data/lib/patchelf/cli.rb
CHANGED
|
@@ -9,7 +9,7 @@ module PatchELF
|
|
|
9
9
|
# For command line interface to parsing arguments.
|
|
10
10
|
module CLI
|
|
11
11
|
# Name of binary.
|
|
12
|
-
SCRIPT_NAME = 'patchelf.rb'
|
|
12
|
+
SCRIPT_NAME = 'patchelf.rb'
|
|
13
13
|
# CLI usage string.
|
|
14
14
|
USAGE = format('Usage: %s <commands> FILENAME [OUTPUT_FILE]', SCRIPT_NAME).freeze
|
|
15
15
|
|
data/lib/patchelf/patcher.rb
CHANGED
|
@@ -29,7 +29,7 @@ module PatchELF
|
|
|
29
29
|
# :silent = ignore the errors
|
|
30
30
|
def initialize(filename, on_error: :log, logging: true)
|
|
31
31
|
@in_file = filename
|
|
32
|
-
f = File.open(filename)
|
|
32
|
+
f = File.open(filename) # rubocop:disable Style/FileOpen
|
|
33
33
|
@elf = ELFTools::ELFFile.new(f)
|
|
34
34
|
@set = {}
|
|
35
35
|
@rpath_sym = :runpath
|
data/lib/patchelf/saver.rb
CHANGED
|
@@ -32,7 +32,7 @@ module PatchELF
|
|
|
32
32
|
@set = set
|
|
33
33
|
# [{Integer => String}]
|
|
34
34
|
@inline_patch = {}
|
|
35
|
-
f = File.open(in_file)
|
|
35
|
+
f = File.open(in_file) # rubocop:disable Style/FileOpen
|
|
36
36
|
@elf = ELFTools::ELFFile.new(f)
|
|
37
37
|
@mm = PatchELF::MM.new(@elf)
|
|
38
38
|
@strtab_extend_requests = []
|
data/lib/patchelf/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: patchelf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- david942j
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: elftools
|
|
@@ -93,6 +93,20 @@ dependencies:
|
|
|
93
93
|
- - ">="
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '0.22'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: simplecov-cobertura
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '4'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '4'
|
|
96
110
|
- !ruby/object:Gem::Dependency
|
|
97
111
|
name: tty-platform
|
|
98
112
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -144,11 +158,14 @@ files:
|
|
|
144
158
|
- lib/patchelf/patcher.rb
|
|
145
159
|
- lib/patchelf/saver.rb
|
|
146
160
|
- lib/patchelf/version.rb
|
|
147
|
-
homepage: https://github.com/
|
|
161
|
+
homepage: https://github.com/Homebrew/patchelf.rb
|
|
148
162
|
licenses:
|
|
149
163
|
- MIT
|
|
150
164
|
metadata:
|
|
151
165
|
rubygems_mfa_required: 'true'
|
|
166
|
+
source_code_uri: https://github.com/Homebrew/patchelf.rb
|
|
167
|
+
bug_tracker_uri: https://github.com/Homebrew/patchelf.rb/issues
|
|
168
|
+
funding_uri: https://github.com/sponsors/Homebrew
|
|
152
169
|
rdoc_options: []
|
|
153
170
|
require_paths:
|
|
154
171
|
- lib
|
|
@@ -156,14 +173,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
156
173
|
requirements:
|
|
157
174
|
- - ">="
|
|
158
175
|
- !ruby/object:Gem::Version
|
|
159
|
-
version: '3.
|
|
176
|
+
version: '3.3'
|
|
160
177
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
178
|
requirements:
|
|
162
179
|
- - ">="
|
|
163
180
|
- !ruby/object:Gem::Version
|
|
164
181
|
version: '0'
|
|
165
182
|
requirements: []
|
|
166
|
-
rubygems_version:
|
|
183
|
+
rubygems_version: 4.0.16
|
|
167
184
|
specification_version: 4
|
|
168
185
|
summary: patchelf
|
|
169
186
|
test_files: []
|