Exemple #1
0
static void * do_actual_load(const char * filename, elf_t * lib, int flags) {
	(void)flags;

	if (!lib) {
		last_error = "could not open library (not found, or other failure)";
		return NULL;
	}

	size_t lib_size = object_calculate_size(lib);

	if (lib_size < 4096) {
		lib_size = 4096;
	}

	uintptr_t load_addr = (uintptr_t)malloc(lib_size);
	object_load(lib, load_addr);

	object_postload(lib);

	node_t * item;
	while (item = list_pop(lib->dependencies)) {

		elf_t * lib = open_object(item->value);

		if (!lib) {
			free((void *)load_addr);
			last_error = "Failed to load a dependency.";
			return NULL;
		}

		if (!lib->loaded) {
			do_actual_load(item->value, lib, 0);
			TRACE_LD("Loaded %s at 0x%x", item->value, lib->base);
		}

	}

	TRACE_LD("Relocating %s", filename);
	object_relocate(lib);

	fclose(lib->file);

	if (lib->ctors) {
		for (size_t i = 0; i < lib->ctors_size; i += sizeof(uintptr_t)) {
			TRACE_LD(" 0x%x()", lib->ctors[i]);
			lib->ctors[i]();
		}
	}

	if (lib->init) {
		lib->init();
	}

	return (void *)lib;

}
Exemple #2
0
static DiaObject *
textobj_load(ObjectNode obj_node, int version, DiaContext *ctx)
{
  Textobj *textobj;
  DiaObject *obj;
  AttributeNode attr;
  Point startpoint = {0.0, 0.0};

  textobj = g_malloc0(sizeof(Textobj));
  obj = &textobj->object;
  
  obj->type = &textobj_type;
  obj->ops = &textobj_ops;

  object_load(obj, obj_node, ctx);

  attr = object_find_attribute(obj_node, "text");
  if (attr != NULL) {
    textobj->text = data_text(attribute_first_data(attr), ctx);
  } else {
    DiaFont* font = dia_font_new_from_style(DIA_FONT_MONOSPACE,1.0);
    textobj->text = new_text("", font, 1.0,
			     &startpoint, &color_black, ALIGN_CENTER);
    dia_font_unref(font);
  }

  attr = object_find_attribute(obj_node, "valign");
  if (attr != NULL)
    textobj->vert_align = data_enum(attribute_first_data(attr), ctx);
  else if (version == 0) {
    textobj->vert_align = VALIGN_FIRST_LINE;
  }

  /* default visibility must be off to keep compatibility */
  textobj->fill_color = attributes_get_background();
  attr = object_find_attribute(obj_node, "fill_color");
  if (attr)
    data_color(attribute_first_data(attr), &textobj->fill_color, ctx);
  attr = object_find_attribute(obj_node, "show_background");
  if (attr)
    textobj->show_background = data_boolean(attribute_first_data(attr), ctx);
  else
    textobj->show_background = FALSE;

  object_init(obj, 1, 0);

  obj->handles[0] = &textobj->text_handle;
  textobj->text_handle.id = HANDLE_TEXT;
  textobj->text_handle.type = HANDLE_MAJOR_CONTROL;
  textobj->text_handle.connect_type = HANDLE_CONNECTABLE;
  textobj->text_handle.connected_to = NULL;

  textobj_update_data(textobj);

  return &textobj->object;
}
Exemple #3
0
void
polyconn_load(PolyConn *poly, ObjectNode obj_node, DiaContext *ctx) /* NOTE: Does object_init() */
{
  int i;
  AttributeNode attr;
  DataNode data;
  
  DiaObject *obj = &poly->object;

  object_load(obj, obj_node, ctx);

  attr = object_find_attribute(obj_node, "poly_points");

  if (attr != NULL)
    poly->numpoints = attribute_num_data(attr);
  else
    poly->numpoints = 0;

  object_init(obj, poly->numpoints, 0);

  data = attribute_first_data(attr);
  poly->points = g_malloc(poly->numpoints*sizeof(Point));
  for (i=0;i<poly->numpoints;i++) {
    data_point(data, &poly->points[i], ctx);
    data = data_next(data);
  }

  obj->handles[0] = g_malloc(sizeof(Handle));
  obj->handles[0]->connect_type = HANDLE_CONNECTABLE;
  obj->handles[0]->connected_to = NULL;
  obj->handles[0]->type = HANDLE_MAJOR_CONTROL;
  obj->handles[0]->id = HANDLE_MOVE_STARTPOINT;
  
  obj->handles[poly->numpoints-1] = g_malloc(sizeof(Handle));
  obj->handles[poly->numpoints-1]->connect_type = HANDLE_CONNECTABLE;
  obj->handles[poly->numpoints-1]->connected_to = NULL;
  obj->handles[poly->numpoints-1]->type = HANDLE_MAJOR_CONTROL;
  obj->handles[poly->numpoints-1]->id = HANDLE_MOVE_ENDPOINT;

  for (i=1;i<poly->numpoints-1;i++) {
    obj->handles[i] = g_malloc(sizeof(Handle));
    setup_handle(obj->handles[i], PC_HANDLE_CORNER);
  }

  polyconn_update_data(poly);
}
Exemple #4
0
/**
 * 
 *  rct2: 0x006AA0C6
 */
int object_read_and_load_entries(FILE *file)
{
	object_unload_all();

	int i, j;
	rct_object_entry *entries;

	// Read all the object entries
	entries = malloc(OBJECT_ENTRY_COUNT * sizeof(rct_object_entry));
	sawyercoding_read_chunk(file, (uint8*)entries);

	// Load each object
	for (i = 0; i < OBJECT_ENTRY_COUNT; i++) {
		if (!check_object_entry(&entries[i]))
			continue;

		// Get entry group index
		int entryGroupIndex = i;
		for (j = 0; j < countof(object_entry_group_counts); j++) {
			if (entryGroupIndex < object_entry_group_counts[j])
				break;
			entryGroupIndex -= object_entry_group_counts[j];
		}

		// Load the obect
		if (!object_load(entryGroupIndex, &entries[i])) {
			// Failed to load the object
			free(entries);
			memcpy((char*)0x13CE952, entries[i].name, 8);
			object_unload_all();
			return 0;
		}
	}

	free(entries);
	return 1;
}
Exemple #5
0
void vfs_mount(const struct volume_metadata *md, const char *path) {
  const char *argv[] = {
      "cloudfs", path,
      "-f", "-s",
      "-o", "hard_remove",
      NULL };

  notice("Volume mounting on %s", path);

  misc_maybe_fork();

  object_load();

  vfs_fsid = unique_id();

  if (fuse_main(sizearr(argv) - 1, (char**) argv, &vfs_oper, NULL) != 0)
    warning("FUSE failed");

  notice("Volume disconnecting");

  vfs_fd_clear();
  vfs_node_clear();
  object_unload();
}
Exemple #6
0
/**
 * 
 *  rct2: 0x006A8B40
 */
void object_list_load()
{
	HANDLE hFindFile;
	WIN32_FIND_DATAA findFileData;
	int totalFiles = 0, totalFileSize = 0, fileDateModifiedChecksum = 0;

	char pluginPath[MAX_PATH];
	get_plugin_path(pluginPath);

	// Enumerate through each object in the directory
	hFindFile = FindFirstFile(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), &findFileData);
	if (hFindFile != INVALID_HANDLE_VALUE) {
		do {
			totalFiles++;
			totalFileSize += findFileData.nFileSizeLow;
			fileDateModifiedChecksum ^=
				findFileData.ftLastWriteTime.dwLowDateTime ^
				findFileData.ftLastWriteTime.dwHighDateTime;
			fileDateModifiedChecksum = ror32(fileDateModifiedChecksum, 5);
		} while (FindNextFile(hFindFile, &findFileData));
		FindClose(hFindFile);
	}

	totalFiles = ror32(totalFiles, 24);
	totalFiles = (totalFiles & ~0xFF) | 1;
	totalFiles = rol32(totalFiles, 24);

	// Read plugin header
	rct_plugin_header pluginHeader;

	FILE *file = fopen(pluginPath, "rb");
	if (file != NULL) {
		if (fread(&pluginHeader, sizeof(pluginHeader), 1, file) == 1) {
			// Check if object repository has changed in anyway
			if (
				totalFiles == pluginHeader.total_files &&
				totalFileSize == pluginHeader.total_file_size &&
				fileDateModifiedChecksum == pluginHeader.date_modified_checksum
			) {
				// Dispose installed object list
				if (RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, sint32) != -1) {
					rct2_free(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*));
					RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, sint32) = -1;
				}

				// Read installed object list
				RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*) = rct2_malloc(pluginHeader.object_list_size);
				if (fread(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*), pluginHeader.object_list_size, 1, file) == 1) {
					RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) = pluginHeader.object_list_no_items;

					fclose(file);
					sub_6A9FC0();
					object_list_examine();
					return;
				}
			}
		}
		fclose(file);
	}

	// Reload object list
	RCT2_GLOBAL(0x00F42B94, uint32) = totalFiles;
	RCT2_GLOBAL(0x00F42B98, uint32) = totalFileSize;
	RCT2_GLOBAL(0x00F42B9C, uint32) = fileDateModifiedChecksum;
	//RCT2_CALLPROC_EBPSAFE(0x006A8D8F);

	int eax = 3161;
	if (RCT2_GLOBAL(0x9AA00D, uint8) != 0){
		eax = 3160;
		RCT2_GLOBAL(0x9AA00D, uint8) = 0;
	}
	// File count removed and replaced by variable
	// RCT2_GLOBAL(0xF42BA8, uint32) = 0;
	uint32 file_count = 0;

	// Progress bar related.
	RCT2_GLOBAL(0xF42BD8, uint8) = 0;

	sub_6A9FC0();

	// Dispose installed object list
	if (RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, sint32) != -1) {
		rct2_free(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*));
		RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, sint32) = -1;
	}

	RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) = 0;
	RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*) = rct2_malloc(4096);
	if (RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, int) == -1){
		RCT2_CALLPROC_X(0x006E3838, 0x343, 0xC5A, 0, 0, 0, 0, 0);
		return;
	}

	uint32 installed_buffer_size = 0x1000;
	uint32 current_item_offset = 0;

	hFindFile = FindFirstFile(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), &findFileData);
	if (hFindFile == INVALID_HANDLE_VALUE){
		//6a92ea This hasn't been implemented but there isn't much point.
		// It would make a empty object file if no files found.
		return;
	}

	for (uint8 first_time = 1; first_time || FindNextFile(hFindFile, &findFileData);){
		first_time = 0;

		RCT2_GLOBAL(0x9ABD98, HANDLE) = hFindFile;
		
		file_count++;
		// update progress bar. 
		eax = (file_count << 8) / ((RCT2_GLOBAL(0xF42B94, uint32) & 0xFFFFFF) + 1);



		if ((eax & 0xFF) != RCT2_GLOBAL(0xF42BD8, uint8)){
			RCT2_GLOBAL(0xF42BD8, uint8) = eax & 0xFF;
			// update progress bar
		}

		if ((installed_buffer_size - current_item_offset) <= 2842){
			installed_buffer_size += 0x1000;
			RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*) = rct2_realloc(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*), installed_buffer_size);
			if (RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, int) == -1){
				RCT2_CALLPROC_X(0x006E3838, 0x343, 0xC5A, 0, 0, 0, 0, 0);
				return;
			}
		}

		char path[260];
		subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), findFileData.cFileName);

		FILE *obj_file = fopen(path, "rb");
		if (obj_file == NULL){
			continue;
		}

		rct_object_entry* entry = RCT2_ADDRESS(0xF42B74, rct_object_entry);
		if (fread(entry, sizeof(rct_object_entry), 1, obj_file) != 1){
			fclose(obj_file);
			continue;
		}
		fclose(obj_file);

		RCT2_GLOBAL(0xF42BC4, uint32) = current_item_offset;

		uint8* installed_entry_pointer = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, uint8*) + current_item_offset;

		memcpy(installed_entry_pointer, entry, sizeof(rct_object_entry));
		installed_entry_pointer += sizeof(rct_object_entry);

		strcpy(installed_entry_pointer, findFileData.cFileName);
		while (*installed_entry_pointer++);

		*((sint32*)installed_entry_pointer) = -1;
		*(installed_entry_pointer + 4) = 0;
		*((sint32*)(installed_entry_pointer + 5)) = 0;
		*((uint16*)(installed_entry_pointer + 9)) = 0;
		*((uint32*)(installed_entry_pointer + 11)) = 0;

		RCT2_GLOBAL(0x9ADAF0, uint32) = 0xF26E;

		RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32)++;

		// This is a variable used by object_load to decide if it should
		// use object_paint on the entry.
		RCT2_GLOBAL(0x9ADAFD, uint8) = 1;

		// Probably used by object paint.
		RCT2_GLOBAL(0x9ADAF4, uint32) = 0xF42BDB;

		int chunk_size;
		if (!object_load(-1, entry, &chunk_size)){
			RCT2_GLOBAL(0x9ADAF4, sint32) = -1;
			RCT2_GLOBAL(0x9ADAFD, uint8) = 0;
			RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32)--;
			continue;
		}
		// See above note
		RCT2_GLOBAL(0x9ADAF4, sint32) = -1;
		RCT2_GLOBAL(0x9ADAFD, uint8) = 0;

		if ((entry->flags & 0xF0) == 0x80){
			RCT2_GLOBAL(0xF42B70, uint32)++;
			if (RCT2_GLOBAL(0xF42B70, uint32) > 772){
				RCT2_GLOBAL(0xF42B70, uint32)--;
				RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32)--;
				continue;
			}
		}
		*((sint32*)installed_entry_pointer) = chunk_size;
		installed_entry_pointer += 4;

		uint8* chunk = RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_CHUNK_POINTER, uint8*); // Loaded in object_load

		// When made of two parts i.e Wooden Roller Coaster (Dream Woodie Cars);
		if ((entry->flags & 0xF) == 0 && !(*((uint32*)(chunk + 8)) & 0x1000)){
			rct_string_id obj_string = chunk[12];
			if (obj_string == 0xFF){
				obj_string = chunk[13];
				if (obj_string == 0xFF){
					obj_string = chunk[14];
				}
			}

			obj_string += 2;
			format_string(installed_entry_pointer, obj_string, 0);
			strcat(installed_entry_pointer, "\t (");
			strcat(installed_entry_pointer, language_get_string(RCT2_GLOBAL(0xF42BBC, uint32)));
			strcat(installed_entry_pointer, ")");
			while (*installed_entry_pointer++);
		}
		else{
			strcpy(installed_entry_pointer, language_get_string(RCT2_GLOBAL(0xF42BBC, uint32)));
			while (*installed_entry_pointer++);
		}
		*((uint32*)installed_entry_pointer) = RCT2_GLOBAL(0x9ADAF0, uint32) - 0xF26E;
		installed_entry_pointer += 4;

		uint8* esi = RCT2_ADDRESS(0xF42BDB, uint8);
		int cl = *esi++;
		*installed_entry_pointer++ = cl;
		if (cl){
			memcpy(installed_entry_pointer, esi, cl*sizeof(rct_object_entry));
			installed_entry_pointer += cl*sizeof(rct_object_entry);
		}

		cl = *esi++;
		*installed_entry_pointer++ = cl;
		if (cl){
			memcpy(installed_entry_pointer, esi, cl*sizeof(rct_object_entry));
			installed_entry_pointer += cl*sizeof(rct_object_entry);
		}

		*((uint32*)installed_entry_pointer) = RCT2_GLOBAL(0xF433DD, uint32);
		installed_entry_pointer += 4;

		int size_of_object = installed_entry_pointer - RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, uint8*) - current_item_offset;

		object_unload(entry->flags & 0xF, (rct_object_entry_extended*)entry);

		// Return pointer to start of entry
		installed_entry_pointer -= size_of_object;

		uint8* copied_entry = RCT2_ADDRESS(0x140E9AC, uint8);

		size_of_object = object_copy(copied_entry, installed_entry_pointer);

		RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32)--;
		copied_entry += sizeof(rct_object_entry);
		// Skip filename
		while (*copied_entry++);

		// Skip 
		copied_entry += 4;

		installed_entry_pointer = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, uint8*);

		for (uint32 i = 0; i < RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); ++i){

			uint8* temp_installed_entry = installed_entry_pointer;
			temp_installed_entry += sizeof(rct_object_entry);

			// Skip filename
			while (*temp_installed_entry++);

			// Skip 
			temp_installed_entry += 4;

			if (strcmp(temp_installed_entry, copied_entry) <= 0)break;

			installed_entry_pointer = (uint8*)(object_get_next((rct_object_entry*)installed_entry_pointer));
		}

		// Difference to new location
		int no_bytes_to_move = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, uint8*) + current_item_offset - installed_entry_pointer;

		uint8* curr_location = installed_entry_pointer;
		uint8* move_location = installed_entry_pointer + size_of_object;

		if (no_bytes_to_move){
			memmove(move_location, curr_location, no_bytes_to_move);
		}

		copied_entry = RCT2_ADDRESS(0x140E9AC, uint8);
		memcpy(installed_entry_pointer, copied_entry, size_of_object);
		current_item_offset += size_of_object;
		RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32)++;
	}
Exemple #7
0
static DiaObject *
compound_load (ObjectNode obj_node, int version, DiaContext *ctx)
{
  Compound * comp;
  DiaObject * obj;
  AttributeNode attr;
  DataNode data;
  gint i, num_handles;

  comp = g_new0 (Compound, 1);
  obj = &comp->object;
  /* load the objects position and bounding box */
  object_load (obj, obj_node, ctx);
  /* init the object */
  obj->type = &compound_type;
  obj->ops = &compound_ops;

  /* load the object's handles and its positions */
  attr = object_find_attribute (obj_node, "comp_points");
  g_assert (attr != NULL);
  num_handles = attribute_num_data (attr);
  g_assert (num_handles >= 3);
  /* allocate space for object handles and connectionpoints point arrays */
  object_init (obj, num_handles, 1);
  data = attribute_first_data (attr);
  /* init our mount_point */
  setup_mount_point (&comp->mount_point, obj, NULL);
  data_point (data, &comp->mount_point.pos, ctx);
  obj->connections[0] = &comp->mount_point;
  /* now init the handles */
  comp->num_arms = num_handles-1;
  comp->handles = g_new0 (Handle, num_handles);
  setup_handle (&comp->handles[0], HANDLE_MOUNT_POINT,
                HANDLE_MAJOR_CONTROL, HANDLE_NONCONNECTABLE);
  comp->handles[0].pos = comp->mount_point.pos;
  obj->handles[0] = &comp->handles[0];
  data = data_next (data);
  for (i = 1; i < num_handles; i++)
    {
      obj->handles[i] = &comp->handles[i];
      setup_handle (obj->handles[i], HANDLE_ARM,
                    HANDLE_MINOR_CONTROL, HANDLE_CONNECTABLE_NOBREAK);
      data_point (data, &obj->handles[i]->pos, ctx);
      data = data_next (data);
    }

  /* load remainding properties */
  attr = object_find_attribute (obj_node, PROP_STDTYPE_LINE_WIDTH);
  if (attr == NULL)
    comp->line_width = 0.1;
  else
    comp->line_width = data_real (attribute_first_data (attr), ctx);
  attr = object_find_attribute (obj_node, "line_colour");
  if (attr == NULL)
    comp->line_color = color_black;
  else
    data_color (attribute_first_data (attr), &comp->line_color, ctx);

  compound_update_data (comp);
  compound_sanity_check (comp, "Loaded");
  return &comp->object;
}
Exemple #8
0
int main(int argc, char * argv[]) {

	char * file = argv[1];
	size_t arg_offset = 1;

	if (!strcmp(argv[1], "-e")) {
		arg_offset = 3;
		file = argv[2];
	}

	char * trace_ld_env = getenv("LD_DEBUG");
	if (trace_ld_env && (!strcmp(trace_ld_env,"1") || !strcmp(trace_ld_env,"yes"))) {
		__trace_ld = 1;
	}

	dumb_symbol_table = hashmap_create(10);
	glob_dat = hashmap_create(10);
	objects_map = hashmap_create(10);

	ld_exports_t * ex = ld_builtin_exports;
	while (ex->name) {
		hashmap_set(dumb_symbol_table, ex->name, ex->symbol);
		ex++;
	}

	elf_t * main_obj = open_object(file);
	_main_obj = main_obj;

	if (!main_obj) {
		fprintf(stderr, "%s: error: failed to open object '%s'.\n", argv[0], file);
		return 1;
	}

	size_t main_size = object_calculate_size(main_obj);
	uintptr_t end_addr = object_load(main_obj, 0x0);
	object_postload(main_obj);

	object_find_copy_relocations(main_obj);

	hashmap_t * libs = hashmap_create(10);

	list_t * ctor_libs = list_create();
	list_t * init_libs = list_create();

	TRACE_LD("Loading dependencies.");
	node_t * item;
	while (item = list_pop(main_obj->dependencies)) {
		while (end_addr & 0xFFF) {
			end_addr++;
		}

		char * lib_name = item->value;
		if (!strcmp(lib_name, "libg.so")) goto nope;
		elf_t * lib = open_object(lib_name);
		if (!lib) {
			fprintf(stderr, "Failed to load dependency '%s'.\n", lib_name);
			return 1;
		}
		hashmap_set(libs, lib_name, lib);

		TRACE_LD("Loading %s at 0x%x", lib_name, end_addr);
		end_addr = object_load(lib, end_addr);
		object_postload(lib);
		TRACE_LD("Relocating %s", lib_name);
		object_relocate(lib);

		fclose(lib->file);

		/* Execute constructors */
		if (lib->ctors) {
			list_insert(ctor_libs, lib);
		}
		if (lib->init) {
			list_insert(init_libs, lib);
		}

nope:
		free(item);
	}

	TRACE_LD("Relocating main object");
	object_relocate(main_obj);
	TRACE_LD("Placing heap at end");
	while (end_addr & 0xFFF) {
		end_addr++;
	}

	char * ld_no_ctors = getenv("LD_DISABLE_CTORS");
	if (ld_no_ctors && (!strcmp(ld_no_ctors,"1") || !strcmp(ld_no_ctors,"yes"))) {
		TRACE_LD("skipping ctors because LD_DISABLE_CTORS was set");
	} else {
		foreach(node, ctor_libs) {
			elf_t * lib = node->value;
			if (lib->ctors) {
				TRACE_LD("Executing ctors...");
				for (size_t i = 0; i < lib->ctors_size; i += sizeof(uintptr_t)) {
					TRACE_LD(" 0x%x()", lib->ctors[i]);
					lib->ctors[i]();
				}
			}
		}
	}