Class: RMasm::DataItem

Inherits:
BinaryDirective show all
Defined in:
lib/rmasm/data_core.rb

Overview

RMasm::DataItem represents a single data declaration in a program.

The following primitive are defined at a global scope :

  • db : a byte (8 bits)

  • dw : a word (16 bits)

  • dd : a double word (32 bits)

  • dq : a quad word (64 bits)

  • float: a 32 bits floating point

  • float2: a vector of 2 floats

  • float3: a vector of 3 floats

  • float4: a vector of 4 floats.

A declaration can accept multiple declaration on a single line. Each declaration item could be

  • a NUMERIC value: declare a datatype with a default value

    example : db 0            # initialize a byte with the 0 value
              float 1.5       # initialize a float with the 1.5 value
              dd 1555         # initialize a dword with the dword value 1555
              MyStruct 0      # Initialize MyStruct using the 0 value as the default byte values for the struct
    
  • a SYMBOL :symbol value: declare a datatype with an attached label to it and a default value that is equal to data.default.value. There are 2 cases in the symbol :

    - the symbol starts with a @. This symbol is considered as an address referencing the :xxxx symbol
        example : dd :@other_symbol      # initialize a dword with the adress of :other_symbol
    
    - otherwise, if the symbol is a plain symbol, this is equivalent to declare :nil[0 => data.default.value]
        example : dd :a                  # initialize a dword accessible from the label :a
    
  • a SYMBOL ARRAY :symbol, declare an array of the datatype. The array_size can be :

    - an integer value : like in :my_symbol[50]. Declare an array with 50 elements. If this value == 0, then the
      array is considered as a variable array. Note that you cannot use an array with a struct that contains a
      variable array.
    - an association integer => default_value, like in :my_symbol[50 => 1], Declare an array of 50 elements with
      default value 1. The value should be the same type as the datatype.
    - if the symbol is :nil, then the array is an anonymous array (no labels are emitted)
    
  • a plain ARRAY [array_size], that depends on the datatype :

    - if the datatype is a primitive, the array declare an array of datatype with array_size elements. The default
      value can be affected as well as for the :symbol[array_size]
        example : db [50]             # initialize 50 bytes with the value = data.default.value
                  dd [50 => 1]        # initialize 50 dword with the dword value 1
    
    - if the datatype is a struct, then the array is considered to fill the structure
        example: with have a basic struct :MyStruct { db :a; dw :b; dd :c }
                 MyStruct [0, 1, 2]   # initialize a MyStruct this MyStruct.a = 0, MyStruct.b = 1, MyStruct.c = 2
    
  • a plain HASH { key => value, …} that depends on the datatype :

    - if the datatype is a primitive, the key is an integer and represents an index with associated value
        example : db { 5 => 1, 50 => 2}  # initialize an array of 51 elements with the data.default.value. But
                  set the 5th element to 1 and the 50th element to 2
    
    - if the datatype is a struct, then the key are considered as named parameters for the struct
        example : MyStruct { :b => 1, :c => 2, :a => 1 }  # initialize a MyStruct this MyStruct.a = 0,
                  MyStruct.b = 1, MyStruct.c = 2. Remark that you can initialize the fields in any orders you want
                  if the field is not supplied, the whole structure is by default fill with the data.default.value
    
  • an EXPRESSION element: when performing operations with :@symbols

    example : dd :first_array[50]
              dd (:@_ - :@first_array)   # is equivalent to calculate the sizeof(:first_array), or :first_array.sizeof
    
  • a STRING used with the byte datatype (or char datatype for unicode strings)

    example : db "this is rmasm in action", 0    # initialize a null terminated string of bytes
              dc "this is rmasm in action", 0    # initialize a null terminated string of char (can be byte or word)
    

SYMBOL declaration can the be initialized with the << operator

example : db :xxxx[50] << [0,1,2,3] << { 4..9 => 4, 10 => 5, 11..-1 => 255 }
        # initialize an array of 50 bytes with the 4 first value equals to 0, 1, 2, 3
        # then the :xxxx[4] to :xxxx[9] will be set to 4
        # then the value :xxxx[10] = 5
        # remaining values are set to 255, meaning that :xxxx[11..49] = 255

Direct Known Subclasses

PrimitiveDataItem, StructDataItem

Instance Attribute Summary collapse

Attributes inherited from Directive

#id

Class Method Summary collapse

Methods included from IBinIOWriter

#_binary_read, #_binary_write, #binary_read, #binary_write, #from_binary, #to_binary

Methods inherited from Directive

#fetch

Instance Attribute Details

#array_sizeObject (readonly)

Returns the value of attribute array_size.



155
156
157
# File 'lib/rmasm/data_core.rb', line 155

def array_size
  @array_size
end

#default_valueObject (readonly)

Returns the value of attribute default_value.



155
156
157
# File 'lib/rmasm/data_core.rb', line 155

def default_value
  @default_value
end

#symbolObject (readonly)

Returns the value of attribute symbol.



155
156
157
# File 'lib/rmasm/data_core.rb', line 155

def symbol
  @symbol
end

#typeObject (readonly)

Returns the value of attribute type.



155
156
157
# File 'lib/rmasm/data_core.rb', line 155

def type
  @type
end

Class Method Details

.decode(type, value) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/rmasm/data_core.rb', line 194

def self.decode(type, value)
  symbol = :nil
  default_value = Data::DEFAULT.value
  initial_default_value = default_value
  value_ext = default_value
  array_size = nil

  is_prim = type.is_primitive?

  check_the_default_value = nil

  if value.is_a?(Numeric)
    value_ext = value
  elsif value.is_a?(String)
    value_ext = value
  elsif value.is_a?(Symbol)
    symbol = value
  elsif value.is_a?(Array)
    if is_prim
      array_size, default_value, value_ext = decode_array_size(value)
    else
      value_ext = value
    end
  elsif value.is_a?(Hash)
    if is_prim
      # if value is a hash, then consider this has a variable array with hash value initialization
      array_size, default_value, value_ext = decode_array_size([0, value])
    else
      # else the value must be interpreted by the struct
      value_ext = value
    end
  elsif value.is_a?(RMasm::SymbolModifier)
    symbol = value.symbol
    array_size, default_value, value_ext2 = decode_array_size(value.size)
    value_ext = (value_ext2.nil?)? value.value : value_ext2 + value.value
  else
    return Report.error(:R4053, value.class, type, value)
  end

  # Check if the default value is changed
  if default_value != initial_default_value
    if is_prim
      return Report.error(:R4033, default_value, type, type.range) if !type.valid?(default_value)
    else
      return Report.error(:R4062, default_value, type) if !Byte.valid?(default_value)
    end
  end

  if is_prim
    return PrimitiveDataItem.new(type, symbol, array_size, default_value, value_ext)
  end
  return StructDataItem.new(type, symbol, array_size, default_value, value_ext)
end

.decode_array_size(value) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/rmasm/data_core.rb', line 157

def self.decode_array_size(value)
  # Return [array_size, default_value, init_values]
  default_value = Data::DEFAULT.value
  array_size = value

  # If value is an array then expect the first one to be the array size description
  if value.is_a?(Array)
    return [Report.error(:R4041, value)]*3 if value.empty?
    array_size = value.shift
    if value.empty?
      value = nil
    end
  else
    # if the value is not an array, then set this value to nil, array_size contains now the value
    value = nil
  end

  # If we have a Hash as an array_size, this is a [size => default_value]
  if array_size.is_a?(Hash)
    # Check the the size of the array is correct
    return [Report.error(:R4011, array_size)]*3 if array_size.size != 1

    new_size, default_value = array_size.shift

    # Check that key is a positive integer
    return [Report.error(:R4022, new_size, "#{new_size} => #{default_value}")]*3 if !(new_size.is_a?(Integer) && new_size >= 0)

    array_size = new_size
  elsif !(array_size.is_a?(Integer) && array_size >= 0)
    return [Report.error(:R4022, array_size, array_size)]*3
  end

  # return the decoding
  [array_size, default_value, value]
end

.fetch(type, value) ⇒ Object



248
249
250
251
# File 'lib/rmasm/data_core.rb', line 248

def self.fetch(type, value)
  data = decode(type, value)
  data.fetch if !data.nil?
end