klinker/driver/
mod.rs

1use crate::driver::errors::{LinkError, ProcessingError};
2use crate::tables::{
3    ContextHash, DataTable, Function, MasterSymbolEntry, NameTable, NameTableEntry, ObjectData,
4    SymbolTable, TempInstr, TempOperand,
5};
6use crate::CLIConfig;
7use errors::LinkResult;
8use kerbalobjects::ko::sections::DataIdx;
9use kerbalobjects::ko::symbols::{SymBind, SymType};
10use kerbalobjects::ko::KOFile;
11use kerbalobjects::ksm::sections::{
12    ArgIndex, ArgumentSection, CodeSection, DebugEntry, DebugRange, DebugSection,
13};
14use kerbalobjects::ksm::KSMFile;
15use kerbalobjects::ksm::{Instr, KSMFileBuilder};
16use kerbalobjects::{KOSValue, Opcode};
17use std::collections::hash_map::DefaultHasher;
18use std::collections::HashMap;
19use std::hash::{Hash, Hasher};
20use std::num::NonZeroUsize;
21use std::panic;
22use std::path::PathBuf;
23use std::thread::{self, JoinHandle};
24
25pub mod reader;
26use reader::Reader;
27
28use self::errors::{FileErrorContext, FuncErrorContext};
29
30pub mod errors;
31
32pub struct Driver {
33    config: CLIConfig,
34    thread_handles: Vec<JoinHandle<LinkResult<ObjectData>>>,
35}
36
37impl Driver {
38    pub fn new(config: CLIConfig) -> Self {
39        Driver {
40            config,
41            thread_handles: Vec::with_capacity(16),
42        }
43    }
44
45    pub fn add(&mut self, path: impl Into<PathBuf>) {
46        let path = path.into();
47
48        let handle = thread::spawn(move || {
49            let (file_name, kofile) = Reader::read_file(path)?;
50            Reader::process_file(file_name, kofile)
51        });
52        self.thread_handles.push(handle);
53    }
54
55    pub fn add_file(&mut self, file_name: String, kofile: KOFile) {
56        let handle = thread::spawn(move || Reader::process_file(file_name, kofile));
57        self.thread_handles.push(handle);
58    }
59
60    pub fn link(&mut self) -> LinkResult<KSMFile> {
61        let mut object_data = Vec::with_capacity(self.thread_handles.len());
62
63        for handle in self.thread_handles.drain(..) {
64            let data = match handle.join() {
65                Ok(obj_data) => obj_data?,
66                Err(e) => panic::resume_unwind(e),
67            };
68
69            object_data.push(data);
70        }
71
72        let init_hash = {
73            let mut hasher = DefaultHasher::new();
74
75            hasher.write("_init".as_bytes());
76
77            hasher.finish()
78        };
79
80        let entry_point_hash = {
81            let mut hasher = DefaultHasher::new();
82            hasher.write(self.config.entry_point.as_bytes());
83            hasher.finish()
84        };
85
86        let mut master_data_table = DataTable::new();
87        let mut master_symbol_table = NameTable::<MasterSymbolEntry>::new();
88        let mut master_function_vec = Vec::new();
89        let mut init_function = None;
90        let mut start_function = None;
91        let mut master_function_name_table = NameTable::<NonZeroUsize>::new();
92        let mut file_name_table = NameTable::<()>::new();
93        let mut master_comment: Option<String> = None;
94
95        let mut temporary_function_vec = Vec::new();
96
97        let builder = KSMFileBuilder::new();
98        let mut arg_section = ArgumentSection::new();
99        // We only have one single code section that contains all executable instructions
100        let mut code_section = CodeSection::new(kerbalobjects::ksm::sections::CodeType::Main);
101
102        // Maps data hashes to arg section indexes
103        let mut data_hash_map = HashMap::<u64, ArgIndex>::new();
104        // Maps function name hashes to absolute instruction indexes
105        let mut func_hash_map = HashMap::<u64, usize>::new();
106        // Keeps track of all of the functions that are referenced
107        let mut func_ref_vec: Vec<u64> = Vec::new();
108        // Variable to keep track of the current absolute index of each function
109        let mut func_offset = 0;
110
111        // Resolve all symbols
112        for (object_data_index, data) in object_data.iter_mut().enumerate() {
113            let mut hasher = DefaultHasher::new();
114            hasher.write(data.input_file_name.as_bytes());
115            let file_name_hash = ContextHash::FileNameHash(hasher.finish());
116            let file_entry = NameTableEntry::from(data.input_file_name.to_owned(), ());
117            let file_name_index = file_name_table.insert(file_entry);
118
119            // Add all function names
120            for mut func_entry in data.function_name_table.drain() {
121                // Update the file name index
122                func_entry.set_value(file_name_index);
123                master_function_name_table.insert(func_entry);
124            }
125
126            // Set all function object data indexes
127            for func in data.function_table.functions_mut() {
128                func.set_object_data_index(object_data_index);
129            }
130            for func in data.local_function_table.functions_mut() {
131                func.set_object_data_index(object_data_index);
132            }
133
134            // Resolve all symbols in this file
135            Driver::resolve_symbols(
136                &mut master_symbol_table,
137                &mut master_data_table,
138                &master_function_name_table,
139                file_name_hash,
140                data,
141                &mut master_comment,
142                entry_point_hash,
143            )?;
144
145            // Add all of the data in this file
146            for value in data.data_table.entries() {
147                master_data_table.add(value.clone());
148            }
149        }
150
151        // At this point all of the symbols will have been resolved. Now we should check if there
152        // are any external symbols left (bad!)
153        for symbol_entry in master_symbol_table.entries() {
154            if symbol_entry.value().internal().sym_bind == SymBind::Extern {
155                let name = symbol_entry.name().to_owned();
156                return Err(LinkError::UnresolvedExternalSymbolError(name));
157            }
158        }
159
160        // Loop through all global functions
161        for data in object_data.iter_mut() {
162            for func in data.function_table.drain() {
163                if func.name_hash() == init_hash {
164                    init_function = Some(func);
165                } else if func.name_hash() == entry_point_hash {
166                    start_function = Some(func);
167                } else {
168                    temporary_function_vec.push(func);
169                }
170            }
171        }
172
173        // Add _init and _start to the top if they exist
174        if let Some(init_func) = &init_function {
175            temporary_function_vec.insert(0, init_func.clone());
176            func_ref_vec.push(init_func.name_hash());
177        } else {
178            // If we are a shared library, that is required
179            if self.config.shared {
180                return Err(LinkError::MissingInitFunctionError);
181            }
182        }
183
184        if let Some(start_func) = &start_function {
185            if self.config.shared {
186                return Err(LinkError::EntryInSharedError);
187            }
188
189            // _init should go before _start
190            if init_function.is_some() {
191                temporary_function_vec.insert(1, start_func.clone());
192            } else {
193                temporary_function_vec.insert(0, start_func.clone());
194            }
195
196            func_ref_vec.push(start_func.name_hash());
197        } else {
198            // If we are not a shared library, that is required
199            if !self.config.shared {
200                return Err(LinkError::MissingEntryPointError(
201                    self.config.entry_point.to_owned(),
202                ));
203            }
204        }
205
206        // The two "root" functions for optimization are _init and _start
207        if let Some(init_func) = &init_function {
208            Driver::add_func_refs_optimize(
209                init_func.name_hash(),
210                true,
211                &mut func_ref_vec,
212                init_func.object_data_index(),
213                &mut object_data,
214                &master_symbol_table,
215                &temporary_function_vec,
216            );
217        }
218
219        if let Some(start_func) = &start_function {
220            Driver::add_func_refs_optimize(
221                start_func.name_hash(),
222                true,
223                &mut func_ref_vec,
224                start_func.object_data_index(),
225                &mut object_data,
226                &master_symbol_table,
227                &temporary_function_vec,
228            );
229        }
230
231        // Now add all of the functions that are referenced
232        for data in object_data.iter_mut() {
233            for func in temporary_function_vec.drain(..) {
234                // Check the reference list
235                if func_ref_vec.contains(&func.name_hash()) {
236                    master_function_vec.push(func);
237                }
238            }
239
240            for func in data.local_function_table.drain() {
241                if data.local_function_ref_vec.contains(&func.name_hash()) {
242                    master_function_vec.push(func);
243                }
244            }
245        }
246
247        // Add in the comment if it exists
248        if let Some(comment) = master_comment {
249            let value = KOSValue::String(comment);
250            arg_section.add(value);
251        }
252
253        // Either way we actually want to make sure that kOS knows where to begin executing code
254        // We know that we have some sort of entry point even if not _start
255        // So we will add a `lbrt "@0001"` to make sure that the code begins correctly
256        let begin_label = KOSValue::String(String::from("@0001"));
257        let begin_index = arg_section.add(begin_label);
258        code_section.add(Instr::OneOp(Opcode::Lbrt, begin_index));
259        func_offset += 1;
260
261        // Loop through each function and find it's offset
262        for func in master_function_vec.iter() {
263            func_offset = Driver::calc_func_offset(
264                func,
265                object_data.get_mut(func.object_data_index()).unwrap(),
266                &mut func_hash_map,
267                func_offset,
268            );
269        }
270
271        // Now add the functions to the binary
272        for mut func in master_function_vec {
273            let object_data_index = func.object_data_index();
274            Driver::add_func_to_code_section(
275                &mut func,
276                &mut arg_section,
277                &mut code_section,
278                &master_symbol_table,
279                &master_data_table,
280                &master_function_name_table,
281                &func_hash_map,
282                &mut data_hash_map,
283                object_data.get(object_data_index).unwrap(),
284            )?;
285        }
286
287        let init_section = CodeSection::new(kerbalobjects::ksm::sections::CodeType::Initialization);
288        let func_section = CodeSection::new(kerbalobjects::ksm::sections::CodeType::Function);
289
290        let builder = builder.with_arg_section(arg_section);
291
292        let builder = builder
293            .with_code_section(func_section)
294            .with_code_section(init_section)
295            .with_code_section(code_section);
296
297        let debug_section = DebugSection::new(DebugEntry::new(1).with_range(DebugRange::new(2, 4)));
298
299        Ok(builder.with_debug_section(debug_section).finish())
300    }
301
302    #[allow(clippy::too_many_arguments)]
303    fn add_func_to_code_section(
304        func: &mut Function,
305        arg_section: &mut ArgumentSection,
306        code_section: &mut CodeSection,
307        master_symbol_table: &NameTable<MasterSymbolEntry>,
308        master_data_table: &DataTable,
309        master_function_name_table: &NameTable<NonZeroUsize>,
310        func_hash_map: &HashMap<u64, usize>,
311        data_hash_map: &mut HashMap<u64, ArgIndex>,
312        object_data: &ObjectData,
313    ) -> LinkResult<()> {
314        for (instr_index, instr) in func.drain().into_iter().enumerate() {
315            let concrete = Driver::concrete_instr(
316                instr,
317                arg_section,
318                master_symbol_table,
319                master_data_table,
320                master_function_name_table,
321                func_hash_map,
322                data_hash_map,
323                object_data,
324                func.name_hash(),
325                instr_index,
326            )?;
327
328            code_section.add(concrete);
329        }
330
331        Ok(())
332    }
333
334    fn func_hash_from_op(
335        op: &TempOperand,
336        master_symbol_table: &NameTable<MasterSymbolEntry>,
337        local_symbol_table: &SymbolTable,
338    ) -> Option<(bool, u64)> {
339        // If it is a symbol reference
340        if let TempOperand::SymNameHash(hash) = op {
341            // Local symbols have higher priority
342            if let Some(sym) = local_symbol_table.get_by_hash(*hash) {
343                // If it is a function
344                if sym.internal().sym_type == SymType::Func {
345                    // The boolean represents if it was a global symbol
346                    Some((false, *hash))
347                } else {
348                    None
349                }
350            } else if let Some(sym) = master_symbol_table.get_by_hash(*hash) {
351                if sym.value().internal().sym_type == SymType::Func {
352                    Some((true, *hash))
353                } else {
354                    None
355                }
356            } else {
357                None
358            }
359        } else {
360            None
361        }
362    }
363
364    fn add_func_ref_from_op(
365        op: &TempOperand,
366        func_ref_vec: &mut Vec<u64>,
367        parent_object_data_index: usize,
368        object_data: &mut Vec<ObjectData>,
369        master_symbol_table: &NameTable<MasterSymbolEntry>,
370        temporary_function_vec: &Vec<Function>,
371    ) {
372        if let Some((is_global, hash)) = Driver::func_hash_from_op(
373            op,
374            master_symbol_table,
375            &object_data
376                .get(parent_object_data_index)
377                .unwrap()
378                .local_symbol_table,
379        ) {
380            let referenced_func_opt = {
381                if is_global {
382                    if !func_ref_vec.contains(&hash) {
383                        func_ref_vec.push(hash);
384
385                        let referenced_func = temporary_function_vec
386                            .iter()
387                            .find(|func| func.name_hash() == hash)
388                            .unwrap();
389
390                        let referenced_func_name_hash = referenced_func.name_hash();
391                        let func_object_data_index = referenced_func.object_data_index();
392
393                        Some((referenced_func_name_hash, func_object_data_index))
394                    } else {
395                        None
396                    }
397                } else {
398                    let parent_object_data = object_data.get_mut(parent_object_data_index).unwrap();
399
400                    if !parent_object_data.local_function_ref_vec.contains(&hash) {
401                        parent_object_data.local_function_ref_vec.push(hash);
402
403                        let referenced_func = object_data
404                            .get(parent_object_data_index)
405                            .unwrap()
406                            .local_function_table
407                            .get_by_hash(hash)
408                            .unwrap();
409
410                        let referenced_func_name_hash = referenced_func.name_hash();
411                        let func_object_data_index = referenced_func.object_data_index();
412
413                        Some((referenced_func_name_hash, func_object_data_index))
414                    } else {
415                        None
416                    }
417                }
418            };
419
420            if let Some((referenced_name_hash, referenced_object_data_index)) = referenced_func_opt
421            {
422                // Recurse.
423                Driver::add_func_refs_optimize(
424                    referenced_name_hash,
425                    is_global,
426                    func_ref_vec,
427                    referenced_object_data_index,
428                    object_data,
429                    master_symbol_table,
430                    temporary_function_vec,
431                );
432            }
433        }
434    }
435
436    fn add_func_refs_optimize(
437        func_name_hash: u64,
438        func_is_global: bool,
439        func_ref_vec: &mut Vec<u64>,
440        object_data_index: usize,
441        object_data: &mut Vec<ObjectData>,
442        master_symbol_table: &NameTable<MasterSymbolEntry>,
443        temporary_function_vec: &Vec<Function>,
444    ) {
445        let mut op_vec = Vec::with_capacity(16);
446        let parent_func = if func_is_global {
447            temporary_function_vec
448                .iter()
449                .find(|func| func.name_hash() == func_name_hash)
450                .unwrap()
451        } else {
452            object_data
453                .get(object_data_index)
454                .unwrap()
455                .local_function_table
456                .get_by_hash(func_name_hash)
457                .unwrap()
458        };
459
460        for instr in parent_func.instructions() {
461            match instr {
462                TempInstr::ZeroOp(_) => {}
463                TempInstr::OneOp(_, op1) => {
464                    op_vec.push(*op1);
465                }
466                TempInstr::TwoOp(_, op1, op2) => {
467                    op_vec.push(*op1);
468                    op_vec.push(*op2);
469                }
470            }
471        }
472
473        for op in op_vec {
474            Driver::add_func_ref_from_op(
475                &op,
476                func_ref_vec,
477                object_data_index,
478                object_data,
479                master_symbol_table,
480                temporary_function_vec,
481            );
482        }
483    }
484
485    fn calc_func_offset(
486        func: &Function,
487        object_data: &mut ObjectData,
488        func_hash_map: &mut HashMap<u64, usize>,
489        current_offset: usize,
490    ) -> usize {
491        let size = func.instruction_count();
492
493        if func.is_global() {
494            func_hash_map.insert(func.name_hash(), current_offset);
495        } else {
496            object_data
497                .local_function_hash_map
498                .insert(func.name_hash(), current_offset);
499        }
500
501        current_offset + size
502    }
503
504    #[allow(clippy::too_many_arguments)]
505    fn concrete_instr(
506        temp: TempInstr,
507        arg_section: &mut ArgumentSection,
508        master_symbol_table: &NameTable<MasterSymbolEntry>,
509        master_data_table: &DataTable,
510        master_function_name_table: &NameTable<NonZeroUsize>,
511        func_hash_map: &HashMap<u64, usize>,
512        data_hash_map: &mut HashMap<u64, ArgIndex>,
513        object_data: &ObjectData,
514        func_name_hash: u64,
515        instr_index: usize,
516    ) -> LinkResult<Instr> {
517        let func_name = match object_data
518            .local_function_name_table
519            .get_by_hash(func_name_hash)
520        {
521            Some(func) => func.name(),
522            None => master_function_name_table
523                .get_by_hash(func_name_hash)
524                .unwrap()
525                .name(),
526        };
527
528        match temp {
529            TempInstr::ZeroOp(opcode) => Ok(Instr::ZeroOp(opcode)),
530            TempInstr::OneOp(opcode, op1) => {
531                let op1_idx = Driver::tempop_to_concrete(
532                    op1,
533                    arg_section,
534                    master_symbol_table,
535                    master_data_table,
536                    func_hash_map,
537                    data_hash_map,
538                    object_data,
539                    func_name,
540                    instr_index,
541                )?;
542
543                Ok(Instr::OneOp(opcode, op1_idx))
544            }
545            TempInstr::TwoOp(opcode, op1, op2) => {
546                let op1_idx = Driver::tempop_to_concrete(
547                    op1,
548                    arg_section,
549                    master_symbol_table,
550                    master_data_table,
551                    func_hash_map,
552                    data_hash_map,
553                    object_data,
554                    func_name,
555                    instr_index,
556                )?;
557                let op2_idx = Driver::tempop_to_concrete(
558                    op2,
559                    arg_section,
560                    master_symbol_table,
561                    master_data_table,
562                    func_hash_map,
563                    data_hash_map,
564                    object_data,
565                    func_name,
566                    instr_index,
567                )?;
568
569                Ok(Instr::TwoOp(opcode, op1_idx, op2_idx))
570            }
571        }
572    }
573
574    #[allow(clippy::too_many_arguments)]
575    fn tempop_to_concrete(
576        op: TempOperand,
577        arg_section: &mut ArgumentSection,
578        master_symbol_table: &NameTable<MasterSymbolEntry>,
579        master_data_table: &DataTable,
580        func_hash_map: &HashMap<u64, usize>,
581        data_hash_map: &mut HashMap<u64, ArgIndex>,
582        object_data: &ObjectData,
583        func_name: &String,
584        instr_index: usize,
585    ) -> LinkResult<ArgIndex> {
586        match op {
587            TempOperand::DataHash(hash) => match data_hash_map.get(&hash) {
588                Some(index) => Ok(*index),
589                None => {
590                    // We do this nonsense so that only referenced data is included in the final binary
591                    let value = master_data_table.get_by_hash(hash).unwrap();
592                    let index = arg_section.add(value.clone());
593                    data_hash_map.insert(hash, index);
594
595                    Ok(index)
596                }
597            },
598            TempOperand::SymNameHash(hash) => {
599                let sym = match object_data.local_symbol_table.get_by_hash(hash) {
600                    Some(local_sym) => local_sym.internal(),
601                    None => match master_symbol_table.get_by_hash(hash) {
602                        Some(entry) => entry.value().internal(),
603                        None => {
604                            return Err(LinkError::InvalidSymbolRefError(
605                                func_name.to_owned(),
606                                instr_index,
607                                hash,
608                            ));
609                        }
610                    },
611                };
612
613                match sym.sym_type {
614                    SymType::Func => {
615                        let func_loc = if sym.sym_bind == SymBind::Global {
616                            func_hash_map.get(&hash).unwrap()
617                        } else {
618                            object_data.local_function_hash_map.get(&hash).unwrap()
619                        };
620
621                        // Construct a new String that contains the destination label
622                        let value = KOSValue::String(format!("@{:0>4}", *func_loc));
623
624                        let mut hasher = DefaultHasher::new();
625                        value.hash(&mut hasher);
626                        let data_hash = hasher.finish();
627
628                        match data_hash_map.get(&data_hash) {
629                            Some(index) => Ok(*index),
630                            None => {
631                                let index = arg_section.add(value.clone());
632                                data_hash_map.insert(data_hash, index);
633
634                                Ok(index)
635                            }
636                        }
637                    }
638                    SymType::NoType => {
639                        // SAFETY: As usual, we add 1 so it is safe
640                        let index =
641                            unsafe { NonZeroUsize::new_unchecked(usize::from(sym.value_idx) + 1) };
642
643                        let data_hash = master_data_table.hash_at(index).unwrap();
644
645                        match data_hash_map.get(data_hash) {
646                            Some(index) => Ok(*index),
647                            None => {
648                                let value = master_data_table.get_at(index).unwrap();
649                                let index = arg_section.add(value.clone());
650                                data_hash_map.insert(*data_hash, index);
651
652                                Ok(index)
653                            }
654                        }
655                    }
656                    _ => unreachable!("Symbol type is not of NoType or Func"),
657                }
658            }
659        }
660    }
661
662    fn resolve_symbols(
663        master_symbol_table: &mut NameTable<MasterSymbolEntry>,
664        master_data_table: &mut DataTable,
665        master_function_name_table: &NameTable<NonZeroUsize>,
666        file_name_hash: ContextHash,
667        object_data: &mut ObjectData,
668        comment: &mut Option<String>,
669        entry_point_hash: u64,
670    ) -> LinkResult<()> {
671        for mut symbol in object_data.symbol_table.drain() {
672            let name_entry = object_data
673                .symbol_name_table
674                .get_by_hash(symbol.name_hash())
675                .unwrap();
676
677            // If it is not a local symbol
678            if symbol.internal().sym_bind != SymBind::Local {
679                // If it is a function symbol
680                if symbol.internal().sym_type == SymType::Func {
681                    // Set the context to be correct
682                    symbol.set_context(file_name_hash);
683
684                    // If it is the entry point, try to set the comment
685                    if entry_point_hash == symbol.name_hash() {
686                        *comment = object_data.comment.clone();
687                    }
688                }
689
690                match master_symbol_table.get_by_hash(symbol.name_hash()) {
691                    Some(other_symbol) => {
692                        // If the found symbol is external
693                        if other_symbol.value().internal().sym_bind == SymBind::Extern {
694                            // If this new symbol is _not_ external
695                            if symbol.internal().sym_bind != SymBind::Extern {
696                                let new_data_idx = if symbol.internal().sym_type == SymType::NoType
697                                {
698                                    let data_index = unsafe {
699                                        NonZeroUsize::new_unchecked(
700                                            usize::from(symbol.internal().value_idx) + 1,
701                                        )
702                                    };
703                                    let data = object_data.data_table.get_at(data_index).unwrap();
704
705                                    let (_, non_zero_idx) = master_data_table.add(data.clone());
706
707                                    DataIdx::from(non_zero_idx.get() - 1)
708                                } else {
709                                    // If this is a function, set the data index to the placeholder, it won't be needed
710                                    DataIdx::PLACEHOLDER
711                                };
712
713                                symbol.internal_mut().value_idx = new_data_idx;
714                                let new_symbol = *symbol.internal();
715
716                                let new_symbol_entry =
717                                    MasterSymbolEntry::new(new_symbol, symbol.context());
718
719                                // Replace it
720                                master_symbol_table
721                                    .replace_by_hash(symbol.name_hash(), new_symbol_entry)
722                                    .map_err(|_| {
723                                        LinkError::InternalError(String::from(
724                                            "Symbol name hash invalid.",
725                                        ))
726                                    })?;
727                            }
728                            // If it was external, don't do anything
729                        }
730                        // If it isn't external
731                        else {
732                            // Check if we are not external
733                            if symbol.internal().sym_bind != SymBind::Extern {
734                                // Duplicate symbol!
735
736                                let file_error_context = FileErrorContext {
737                                    input_file_name: object_data.input_file_name.to_owned(),
738                                    source_file_name: object_data.source_file_name.to_owned(),
739                                };
740
741                                let mut func_error_context = FuncErrorContext {
742                                    file_context: file_error_context.clone(),
743                                    func_name: String::new(),
744                                };
745
746                                let mut original_func_name = None;
747
748                                if let ContextHash::FuncNameHash(func_name_hash) =
749                                    other_symbol.value().context()
750                                {
751                                    let original_function_name_entry = master_function_name_table
752                                        .get_by_hash(func_name_hash)
753                                        .unwrap();
754                                    let original_function_name =
755                                        original_function_name_entry.name();
756
757                                    original_func_name = Some(original_function_name.to_owned());
758                                }
759
760                                return Err(match original_func_name {
761                                    Some(name) => {
762                                        func_error_context.func_name = name;
763
764                                        LinkError::FuncContextError(
765                                            func_error_context,
766                                            ProcessingError::DuplicateSymbolError(
767                                                name_entry.name().to_owned(),
768                                                object_data.source_file_name.to_owned(),
769                                            ),
770                                        )
771                                    }
772                                    None => LinkError::FileContextError(
773                                        file_error_context,
774                                        ProcessingError::DuplicateSymbolError(
775                                            name_entry.name().to_owned(),
776                                            object_data.source_file_name.to_owned(),
777                                        ),
778                                    ),
779                                });
780                            }
781                            // If we are external, then just continue
782                        }
783                    }
784                    None => {
785                        let new_symbol = if symbol.internal().sym_type == SymType::NoType {
786                            let data_index = unsafe {
787                                NonZeroUsize::new_unchecked(
788                                    usize::from(symbol.internal().value_idx) + 1,
789                                )
790                            };
791
792                            if let Some(data) = object_data.data_table.get_at(data_index) {
793                                let (_, non_zero_idx) = master_data_table.add(data.clone());
794
795                                let new_data_idx = DataIdx::from(non_zero_idx.get() - 1);
796
797                                symbol.internal_mut().value_idx = new_data_idx;
798                            }
799
800                            *symbol.internal()
801                        } else {
802                            // If this is a function, don't set the data index it won't be needed
803                            *symbol.internal()
804                        };
805
806                        let new_symbol_entry = MasterSymbolEntry::new(new_symbol, symbol.context());
807                        let new_name_entry =
808                            NameTableEntry::from(name_entry.name().to_owned(), new_symbol_entry);
809
810                        master_symbol_table.raw_insert(symbol.name_hash(), new_name_entry);
811                    }
812                }
813            }
814        }
815
816        Ok(())
817    }
818}