#include "clld.h"

#include <iostream.h>
#include <set_error.h>

int resolve_references (List<InternalObjectFile> & obs, List<CodeImport> & cimports,
                        List<InternalObjectFileP> & shlibs ) {

	AVLTree<Str> unrefs;
	
	int result = 0;

	int aktshlibnum = 1;

	bool newused = true;

	while ( newused ) {
		newused = false;
		for (ListItem<InternalObjectFile> * aktob = obs.get_head();
		     aktob;
		     aktob = aktob->get_next()
		    ) {
		
			if (aktob->used) {
				// try to resolve all imports of aktob
				for (ListItem<Import> * aktimp = aktob->imports.rem_head();
				     aktimp;
				     delete aktimp, aktimp = aktob->imports.rem_head()
				    ) {
					
					if (! unrefs.find(aktimp->name)) {
						// search for the aktimp symbol in any object-file
						
						ListItem<InternalObjectFile> * searchob;
						for (searchob = obs.get_head();
						     searchob;
						     searchob = searchob->get_next()
						    ) {
			
							AVLItem<Symbol> * foundexp = searchob->exports.find(Symbol(aktimp->name));
							
							if (foundexp) {
								if (foundexp->isfloat) {
									cerr << "sorry, external floating point symbols not supported, yet.\n";
									searchob = (ListItem<InternalObjectFile> *)0;
									break;
								}
								
								if (! searchob->used) {
									if (searchob->shared) {
										searchob->ShLibNumber = aktshlibnum++;
										if (aktshlibnum >= 45) {
											cerr << "ERROR: maximum number of shared libraries exceeded -\n"
											        "       use '-static' on one or more of your libraries\n";
											searchob = (ListItem<InternalObjectFile> *)0;
											break;
										}
										shlibs.add_tail(searchob);
									}
									searchob->used = true;
									newused = true;
								}
								
								if (aktob->shared) {
									if (foundexp->numerical) {
										cerr << "ERROR: shared-library imports must be resolved by non-numerical\n"
										        "       symbols. Violated by symbol '" << aktimp->name << "',\n"
										        "       imported by shared-library '" << aktob->name << "',\n"
										        "       exported by object '" << searchob->name << "'.\n";
										break;
									}
									
									ListItem<Import> * lii = new ListItem<Import>(
									           Import(foundexp->ivalue, searchob->ShLibNumber, aktimp->name, false)
									                                             );
									aktob->shimports.add_tail(lii);
									
									if (searchob->ShLibNumber == 0) {
										// shared lib imports from main code, so an internal relocation has to be applied
										searchob->intrelocs.add_tail(InternalReloc(aktob, lii));
									}
									
									break;
									
								} else {
									if (searchob->shared && (! foundexp->numerical)) {
										// label reference in code resolved by shared library
										
										ListItem<CodeImport> * lic = new ListItem<CodeImport>(
									            CodeImport(aktimp->offset, searchob->ShLibNumber,
									                       aktimp->name, foundexp->ivalue)
									                                                         );
										cimports.add_tail(lic);
										
										// remember internal relocation has to be applied
										aktob->intrelocs.add_tail(InternalReloc(searchob, (ListItem<Import> *)lic));
									
										break;

									} else {
										NibStr value(foundexp->ivalue, aktimp->nibsize);
										if (foundexp->numerical == false) {
											if (aktimp->nibsize < 5) {
												set_error("label operand too big for import ","("+NtoStr(aktimp->nibsize)+" < 5)");
												value.fail = -1;
											} else {
												searchob->intrelocs.add_tail(InternalReloc(aktob, aktimp->offset));
											}
											
											// test if a non-internal relocation has to be added
											if (aktimp->reloc_demand) {
// cerr << "added reloc at " << aktimp->offset << "\n";
												aktob->relocs.add_tail(Reloc(aktimp->offset));
											}
										}
										if (value.fail) {
											add_error("WARNING: symbol '"+aktimp->name+"', imported by\n"
											          "         object-file '"+aktob->name+"', exported by\n"
											          "         object-file '"+searchob->name+"' with invalid value","");
											cerr << get_error();
										} else {
											unsigned long long tmp = aktob->body.peek(aktimp->offset, aktimp->nibsize);
											tmp += foundexp->ivalue;
											aktob->body.poke(aktimp->offset, tmp, aktimp->nibsize);
										}
										break;
									}
								}
							}
						}
						
						if (! searchob) {
							if (!shared) {
								unrefs.insert(aktimp->name);
								cerr << "ERROR: unable to resolve symbol '" << aktimp->name << "',\n"
								        "       referenced by object-file '" << aktob->name << "'\n";
								if (unrefs.size() > 50) {
									cerr << "ABORT, too many unresolved symbols\n";
									return -1;
								}
								result = -1;
							} else {
								// unreferenced symbol for shared library...
								if (aktimp->nibsize < 5 || (! aktimp->reloc_demand) ) {
									cerr << "ERROR: run-time imports for shared libraries must be\n"
									        "       non-numerical and >= 5 nibbles in size. This is\n"
									        "       not the case with symbol '" << aktimp->name << "'\n"
									        "       referenced by object-file '" << aktob->name << "'\n";
									result = -1;
								} else {
									// add the actual import to the list of imports for the shared library that is created
									aktob->shimports.add_tail(Import(aktimp->offset, 5, aktimp->name, true));
								}
							}
						}
					}					
				}
			}
		}
	}

	return result;
}



syntax highlighted by Code2HTML, v. 0.9.1