Here is a patch that allow the elf/image view on an ELF file without section.
Celelibi
diff -Naur ht-2.0.18.orig/analyser/elf_analy.cc ht-2.0.18/analyser/elf_analy.cc --- ht-2.0.18.orig/analyser/elf_analy.cc 2007-04-30 12:32:40.000000000 +0200 +++ ht-2.0.18/analyser/elf_analy.cc 2010-10-30 21:05:25.000000000 +0200 @@ -239,18 +239,6 @@ char *name = file->fgetstrz(); if (!name) continue; - switch (sym.st_shndx) { - case ELF_SHN_UNDEF: - break; - case ELF_SHN_ABS: - break; - case ELF_SHN_COMMON: - break; - default: - // sym.st_shndx - break; - } - const char *bind; switch (ELF32_ST_BIND(sym.st_info)) { case ELF_STB_LOCAL: @@ -343,19 +331,6 @@ char *name = file->fgetstrz(); if (!name) continue; - switch (sym.st_shndx) { - case ELF_SHN_UNDEF: - break; - case ELF_SHN_ABS: - break; - case ELF_SHN_COMMON: - break; - default: { - // sym.st_shndx - break; - } - } - const char *bind; switch (ELF64_ST_BIND(sym.st_info)) { case ELF_STB_LOCAL: @@ -550,7 +525,7 @@ FileOfs ofs; ELFAddress ea; if (!convertAddressToELFAddress(Addr, &ea)) return INVALID_FILE_OFS; - if (!elf_addr_to_ofs(&elf_shared->sheaders, elf_shared->ident.e_ident[ELF_EI_CLASS], ea, &ofs)) return INVALID_FILE_OFS; + if (!elf_addr_to_ofs(&elf_shared->sheaders, &elf_shared->pheaders, elf_shared->ident.e_ident[ELF_EI_CLASS], ea, &ofs)) return INVALID_FILE_OFS; return ofs; } else { return INVALID_FILE_OFS; @@ -722,47 +697,92 @@ */ bool ElfAnalyser::validAddress(Address *Addr, tsectype action) { - elf_section_headers *sections=&elf_shared->sheaders; - int sec; + elf_section_headers *sections = &elf_shared->sheaders; + elf_program_headers *segments = &elf_shared->pheaders; + int seg, sec; byte cls = elf_shared->ident.e_ident[ELF_EI_CLASS]; ELFAddress ea; if (!convertAddressToELFAddress(Addr, &ea)) return false; - if (!elf_addr_to_section(sections, cls, ea, &sec)) return false; - switch (cls) { - case ELFCLASS32: { - ELF_SECTION_HEADER32 *s = sections->sheaders32 + sec; - switch (action) { - case scvalid: - return true; - case scread: - return true; - case scwrite: - case screadwrite: - return s->sh_flags & ELF_SHF_WRITE; - case sccode: - return (s->sh_flags & ELF_SHF_EXECINSTR) && (s->sh_type == ELF_SHT_PROGBITS); - case scinitialized: - return s->sh_type==ELF_SHT_PROGBITS; + + // Try to check address validity with respect to sections if they exists + // Otherwise, check with respect to segments + if (elf_addr_to_section(sections, cls, ea, &sec)) { + // FIXME Segment rights should be taken into account + switch (cls) { + case ELFCLASS32: { + ELF_SECTION_HEADER32 *s = sections->sheaders32 + sec; + switch (action) { + case scvalid: + return true; + case scread: + return true; + case scwrite: + case screadwrite: + return s->sh_flags & ELF_SHF_WRITE; + case sccode: + return (s->sh_flags & ELF_SHF_EXECINSTR) && (s->sh_type == ELF_SHT_PROGBITS); + case scinitialized: + return s->sh_type != ELF_SHT_NOBITS; + } + return false; + } + case ELFCLASS64: { + ELF_SECTION_HEADER64 *s = sections->sheaders64 + sec; + switch (action) { + case scvalid: + return true; + case scread: + return true; + case scwrite: + case screadwrite: + return s->sh_flags & ELF_SHF_WRITE; + case sccode: + return (s->sh_flags & ELF_SHF_EXECINSTR) && (s->sh_type == ELF_SHT_PROGBITS); + case scinitialized: + return s->sh_type != ELF_SHT_NOBITS; + } + return false; + } + } + } else if (elf_addr_to_segment(segments, cls, ea, &seg)) { + switch (cls) { + case ELFCLASS32: { + ELF_PROGRAM_HEADER32 *p = segments->pheaders32 + seg; + switch (action) { + case scvalid: + return true; + case scread: + return p->p_flags & ELF_PF_R; + case scwrite: + return p->p_flags & ELF_PF_W; + case screadwrite: + return (p->p_flags & ELF_PF_R) && (p->p_flags & ELF_PF_W); + case sccode: + return (p->p_flags & ELF_PF_X) && (ea.a32 < (p->p_vaddr + p->p_filesz)); + case scinitialized: + return ea.a32 < (p->p_vaddr + p->p_filesz); + } + return false; + } + case ELFCLASS64: { + ELF_PROGRAM_HEADER64 *p = segments->pheaders64 + seg; + switch (action) { + case scvalid: + return true; + case scread: + return p->p_flags & ELF_PF_R; + case scwrite: + return p->p_flags & ELF_PF_W; + case screadwrite: + return (p->p_flags & ELF_PF_R) && (p->p_flags & ELF_PF_W); + case sccode: + return (p->p_flags & ELF_PF_X) && (ea.a64 < (p->p_vaddr + p->p_filesz)); + case scinitialized: + return ea.a64 < (p->p_vaddr + p->p_filesz); + } + return false; } - return false; - } - case ELFCLASS64: { - ELF_SECTION_HEADER64 *s = sections->sheaders64 + sec; - switch (action) { - case scvalid: - return true; - case scread: - return true; - case scwrite: - case screadwrite: - return s->sh_flags & ELF_SHF_WRITE; - case sccode: - return (s->sh_flags & ELF_SHF_EXECINSTR) && (s->sh_type == ELF_SHT_PROGBITS); - case scinitialized: - return s->sh_type==ELF_SHT_PROGBITS; } - return false; - } } return false; } diff -Naur ht-2.0.18.orig/elfstruc.h ht-2.0.18/elfstruc.h --- ht-2.0.18.orig/elfstruc.h 2008-10-08 18:02:24.000000000 +0200 +++ ht-2.0.18/elfstruc.h 2010-10-04 06:12:19.000000000 +0200 @@ -362,7 +362,11 @@ #define ELF_PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ #define ELF_PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ #define ELF_PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ -#define ELF_PT_PAX_FLAGS 0x65041580 /* Indicates PaX flag markings */ +#define ELF_PT_PAX_FLAGS 0x65041580 /* Indicates PaX flag markings */ + +#define ELF_PF_X 1 +#define ELF_PF_W 2 +#define ELF_PF_R 4 struct ELF_PROGRAM_HEADER32 { elf32_word p_type; diff -Naur ht-2.0.18.orig/htelf.cc ht-2.0.18/htelf.cc --- ht-2.0.18.orig/htelf.cc 2009-04-18 00:39:58.000000000 +0200 +++ ht-2.0.18/htelf.cc 2010-10-30 20:17:01.000000000 +0200 @@ -152,13 +152,17 @@ /* read section headers */ elf_shared->sheaders.count = elf_shared->header32.e_shnum; - if (!elf_shared->sheaders.count) throw MsgException("Zero count for section headers"); - elf_shared->sheaders.sheaders32 = ht_malloc(elf_shared->sheaders.count*sizeof *elf_shared->sheaders.sheaders32); - file->seek(header_ofs+elf_shared->header32.e_shoff); - file->readx(elf_shared->sheaders.sheaders32, elf_shared->sheaders.count*sizeof *elf_shared->sheaders.sheaders32); - for (uint i=0; i < elf_shared->sheaders.count; i++) { - ELF_SECTION_HEADER32 a = elf_shared->sheaders.sheaders32[i]; - createHostStruct(elf_shared->sheaders.sheaders32+i, ELF_SECTION_HEADER32_struct, elf_shared->byte_order); +// if (!elf_shared->sheaders.count) throw MsgException("Zero count for section headers"); + if (!elf_shared->sheaders.count) { + elf_shared->sheaders.sheaders32 = NULL; + } else { + elf_shared->sheaders.sheaders32 = ht_malloc(elf_shared->sheaders.count*sizeof *elf_shared->sheaders.sheaders32); + file->seek(header_ofs+elf_shared->header32.e_shoff); + file->readx(elf_shared->sheaders.sheaders32, elf_shared->sheaders.count*sizeof *elf_shared->sheaders.sheaders32); + for (uint i=0; i < elf_shared->sheaders.count; i++) { + ELF_SECTION_HEADER32 a = elf_shared->sheaders.sheaders32[i]; + createHostStruct(elf_shared->sheaders.sheaders32+i, ELF_SECTION_HEADER32_struct, elf_shared->byte_order); + } } /* read program headers */ @@ -198,13 +202,17 @@ /* read section headers */ elf_shared->sheaders.count=elf_shared->header64.e_shnum; - if (!elf_shared->sheaders.count) throw MsgException("Zero count for section headers"); - elf_shared->sheaders.sheaders64 = ht_malloc(elf_shared->sheaders.count*sizeof *elf_shared->sheaders.sheaders64); - file->seek(header_ofs+elf_shared->header64.e_shoff); - file->readx(elf_shared->sheaders.sheaders64, elf_shared->sheaders.count*sizeof *elf_shared->sheaders.sheaders64); - for (uint i=0; i<elf_shared->sheaders.count; i++) { - ELF_SECTION_HEADER64 a = elf_shared->sheaders.sheaders64[i]; - createHostStruct(elf_shared->sheaders.sheaders64+i, ELF_SECTION_HEADER64_struct, elf_shared->byte_order); +// if (!elf_shared->sheaders.count) throw MsgException("Zero count for section headers"); + if (!elf_shared->sheaders.count) { + elf_shared->sheaders.sheaders64 = NULL; + } else { + elf_shared->sheaders.sheaders64 = ht_malloc(elf_shared->sheaders.count*sizeof *elf_shared->sheaders.sheaders64); + file->seek(header_ofs+elf_shared->header64.e_shoff); + file->readx(elf_shared->sheaders.sheaders64, elf_shared->sheaders.count*sizeof *elf_shared->sheaders.sheaders64); + for (uint i=0; i<elf_shared->sheaders.count; i++) { + ELF_SECTION_HEADER64 a = elf_shared->sheaders.sheaders64[i]; + createHostStruct(elf_shared->sheaders.sheaders64+i, ELF_SECTION_HEADER64_struct, elf_shared->byte_order); + } } /* read program headers */ @@ -495,7 +503,25 @@ } case ELFCLASS64: { ELF_SECTION_HEADER64 *s = &sh->sheaders64; - return s->sh_type==ELF_SHT_PROGBITS && s->sh_addr; + return s->sh_type == ELF_SHT_PROGBITS && s->sh_addr; + } + } + return false; +} + +/* + * Tell whether the section will probably be loaded in memory + */ +bool elf_in_mem_section(elf_section_header *sh, uint elfclass) +{ + switch (elfclass) { + case ELFCLASS32: { + ELF_SECTION_HEADER32 *s = &sh->sheaders32; + return (s->sh_type == ELF_SHT_PROGBITS || s->sh_type == ELF_SHT_NOBITS) && s->sh_addr; + } + case ELFCLASS64: { + ELF_SECTION_HEADER64 *s = &sh->sheaders64; + return (s->sh_type == ELF_SHT_PROGBITS || s->sh_type == ELF_SHT_NOBITS) && s->sh_addr; } } return false; @@ -506,39 +532,86 @@ switch (elfclass) { case ELFCLASS32: { ELF_SECTION_HEADER32 *s = &sh->sheaders32; - return (s->sh_type==ELF_SHT_PROGBITS || s->sh_type==ELF_SHT_NOBITS) && s->sh_addr; + return (s->sh_type != ELF_SHT_NULL) && s->sh_addr; } case ELFCLASS64: { ELF_SECTION_HEADER64 *s = &sh->sheaders64; - return (s->sh_type==ELF_SHT_PROGBITS || s->sh_type==ELF_SHT_NOBITS) && s->sh_addr; + return (s->sh_type != ELF_SHT_NULL) && s->sh_addr; } } return false; } -bool elf_addr_to_ofs(elf_section_headers *section_headers, uint elfclass, ELFAddress addr, FileOfs *ofs) +bool elf_addr_to_ofs(elf_section_headers *section_headers, elf_program_headers *segment_headers, uint elfclass, ELFAddress addr, FileOfs *ofs) { switch (elfclass) { case ELFCLASS32: { ELF_SECTION_HEADER32 *s = section_headers->sheaders32; - for (uint i=0; i < section_headers->count; i++) { - if ((elf_phys_and_mem_section((elf_section_header*)s, elfclass)) && (addr.a32 >= s->sh_addr) && (addr.a32 < s->sh_addr+s->sh_size)) { + for (uint i = 0; i < section_headers->count; i++) { + if (elf_phys_and_mem_section((elf_section_header*)s, elfclass) && (addr.a32 >= s->sh_addr) && (addr.a32 < s->sh_addr+s->sh_size)) { *ofs = addr.a32 - s->sh_addr + s->sh_offset; return true; } s++; } + // Not in section ? Falling back to segments + ELF_PROGRAM_HEADER32 *p = segment_headers->pheaders32; + for (uint i = 0; i < segment_headers->count; i++) { + if (p->p_type = ELF_PT_LOAD && (addr.a32 >= p->p_vaddr) && (addr.a32 < p->p_vaddr + p->p_memsz) && (addr.a32 < p->p_vaddr + p->p_filesz)) { + *ofs = addr.a32 - p->p_vaddr + p->p_offset; + return true; + } + p++; + } break; } case ELFCLASS64: { ELF_SECTION_HEADER64 *s = section_headers->sheaders64; for (uint i=0; i < section_headers->count; i++) { - if ((elf_phys_and_mem_section((elf_section_header*)s, elfclass)) && addr.a64 >= s->sh_addr && (addr.a64 < s->sh_addr + s->sh_size)) { + if (elf_phys_and_mem_section((elf_section_header*)s, elfclass) && addr.a64 >= s->sh_addr && (addr.a64 < s->sh_addr + s->sh_size)) { *ofs = addr.a64 - s->sh_addr + s->sh_offset; return true; } s++; } + // Not in section ? Falling back to segments + ELF_PROGRAM_HEADER64 *p = segment_headers->pheaders64; + for (uint i = 0; i < segment_headers->count; i++) { + if (p->p_type = ELF_PT_LOAD && (addr.a64 >= p->p_vaddr) && (addr.a64 < p->p_vaddr + p->p_memsz) && (addr.a64 < p->p_vaddr + p->p_filesz)) { + *ofs = addr.a64 - p->p_vaddr + p->p_offset; + return true; + } + p++; + } + break; + } + } + return false; +} + +bool elf_addr_to_segment(elf_program_headers *segment_headers, uint elfclass, ELFAddress addr, int *segment) +{ + switch (elfclass) { + case ELFCLASS32: { + ELF_PROGRAM_HEADER32 *p = segment_headers->pheaders32; + for (uint i = 0; i < segment_headers->count; i++) { + if (p->p_type = ELF_PT_LOAD && (addr.a32 >= p->p_vaddr) && (addr.a32 < p->p_vaddr + p->p_memsz)) { + *segment = i; + return true; + } + p++; + } + break; + } + case ELFCLASS64: { + ELF_PROGRAM_HEADER64 *p = segment_headers->pheaders64; + for (uint i = 0; i < segment_headers->count; i++) { + if (p->p_type = ELF_PT_LOAD && (addr.a64 >= p->p_vaddr) && (addr.a64 < p->p_vaddr + p->p_memsz)) { + *segment = i; + return true; + } + p++; + } break; } } @@ -551,7 +624,7 @@ case ELFCLASS32: { ELF_SECTION_HEADER32 *s = section_headers->sheaders32; for (uint i = 0; i < section_headers->count; i++) { - if ((elf_valid_section((elf_section_header*)s, elfclass)) && (addr.a32 >= s->sh_addr) && (addr.a32 < s->sh_addr + s->sh_size)) { + if (elf_valid_section((elf_section_header*)s, elfclass) && (addr.a32 >= s->sh_addr) && (addr.a32 < s->sh_addr + s->sh_size)) { *section = i; return true; } @@ -562,7 +635,7 @@ case ELFCLASS64: { ELF_SECTION_HEADER64 *s = section_headers->sheaders64; for (uint i = 0; i < section_headers->count; i++) { - if ((elf_valid_section((elf_section_header*)s, elfclass)) && addr.a64 >= s->sh_addr && (addr.a64 < s->sh_addr + s->sh_size)) { + if (elf_valid_section((elf_section_header*)s, elfclass) && addr.a64 >= s->sh_addr && (addr.a64 < s->sh_addr + s->sh_size)) { *section = i; return true; } diff -Naur ht-2.0.18.orig/htelf.h ht-2.0.18/htelf.h --- ht-2.0.18.orig/htelf.h 2007-04-30 12:23:10.000000000 +0200 +++ ht-2.0.18/htelf.h 2010-10-30 18:40:03.000000000 +0200 @@ -178,16 +178,18 @@ virtual void reloc_apply(Object *reloc, byte *data); virtual bool reloc_unapply(Object *reloc, byte *data); public: - ht_elf32_reloc_file(File *File, bool own_streamfile, ht_elf_shared_data *data); + ht_elf32_reloc_file(File *File, bool own_streamfile, ht_elf_shared_data *data); }; bool isValidELFSectionIdx(ht_elf_shared_data *elf_shared, int idx); bool elf_phys_and_mem_section(elf_section_header *s, uint elfclass); +bool elf_in_mem_section(elf_section_header *s, uint elfclass); bool elf_valid_section(elf_section_header *s, uint elfclass); +bool elf_addr_to_segment(elf_program_headers *segment_headers, uint elfclass, ELFAddress addr, int *segment); bool elf_addr_to_section(elf_section_headers *section_headers, uint elfclass, ELFAddress addr, int *section); -bool elf_addr_to_ofs(elf_section_headers *section_headers, uint elfclass, ELFAddress addr, FileOfs *ofs); +bool elf_addr_to_ofs(elf_section_headers *section_headers, elf_program_headers *segment_headers, uint elfclass, ELFAddress addr, FileOfs *ofs); bool elf_addr_is_valid(elf_section_headers *section_headers, uint elfclass, ELFAddress addr); bool elf_ofs_to_addr(elf_section_headers *section_headers, uint elfclass, FileOfs ofs, ELFAddress *addr); diff -Naur ht-2.0.18.orig/htelfimg.cc ht-2.0.18/htelfimg.cc --- ht-2.0.18.orig/htelfimg.cc 2009-08-27 16:30:57.000000000 +0200 +++ ht-2.0.18/htelfimg.cc 2010-10-30 18:44:50.000000000 +0200 @@ -64,13 +64,26 @@ ELFAddress l, h; l.a32 = (uint32)-1; h.a32 = 0; - ELF_SECTION_HEADER32 *s = elf_shared->sheaders.sheaders32; - for (uint i=0; i<elf_shared->sheaders.count; i++) { - if (elf_valid_section((elf_section_header*)s, elf_shared->ident.e_ident[ELF_EI_CLASS])) { - if (s->sh_addr < l.a32) l.a32=s->sh_addr; - if ((s->sh_addr + s->sh_size > h.a32) && s->sh_size) h.a32=s->sh_addr + s->sh_size - 1; + // Use program headers first since we represent in-memory state. + // But fallback on sections if no program header. + if (elf_shared->pheaders.count) { + ELF_PROGRAM_HEADER32 *p = elf_shared->pheaders.pheaders32; + for (uint i = 0; i < elf_shared->pheaders.count; i++) { + if (p->p_type == ELF_PT_LOAD && p->p_memsz != 0) { + if (p->p_vaddr < l.a32) l.a32 = p->p_vaddr; + if (p->p_vaddr + p->p_memsz > h.a32) h.a32 = p->p_vaddr + p->p_memsz - 1; + } + p++; + } + } else if (elf_shared->sheaders.count) { + ELF_SECTION_HEADER32 *s = elf_shared->sheaders.sheaders32; + for (uint i = 0; i < elf_shared->sheaders.count; i++) { + if (elf_in_mem_section((elf_section_header*)s, elf_shared->ident.e_ident[ELF_EI_CLASS])) { + if (s->sh_addr < l.a32) l.a32 = s->sh_addr; + if ((s->sh_addr + s->sh_size > h.a32) && s->sh_size) h.a32 = s->sh_addr + s->sh_size - 1; + } + s++; } - s++; } low = p->createAddress32(l.a32); high = p->createAddress32(h.a32); @@ -80,16 +93,29 @@ ELFAddress l, h; l.a64 = (uint64)-1; h.a64 = 0; - ELF_SECTION_HEADER64 *s = elf_shared->sheaders.sheaders64; - for (uint i=0; i<elf_shared->sheaders.count; i++) { - if (elf_valid_section((elf_section_header*)s, elf_shared->ident.e_ident[ELF_EI_CLASS])) { - if (s->sh_addr < l.a64) l.a64 = s->sh_addr; - if ((s->sh_addr + s->sh_size > h.a64) - && s->sh_size != 0) { - h.a64 = s->sh_addr + s->sh_size - 1; + // Use program headers first since we represent in-memory state. + // But fallback on sections if no program header. + if (elf_shared->pheaders.count) { + ELF_PROGRAM_HEADER64 *p = elf_shared->pheaders.pheaders64; + for (uint i = 0; i < elf_shared->pheaders.count; i++) { + if (p->p_type == ELF_PT_LOAD && p->p_memsz != 0) { + if (p->p_vaddr < l.a64) l.a64 = p->p_vaddr; + if (p->p_vaddr + p->p_memsz > h.a64) h.a64 = p->p_vaddr + p->p_memsz - 1; } + p++; + } + } else if (elf_shared->sheaders.count) { + ELF_SECTION_HEADER64 *s = elf_shared->sheaders.sheaders64; + for (uint i=0; i<elf_shared->sheaders.count; i++) { + if (elf_valid_section((elf_section_header*)s, elf_shared->ident.e_ident[ELF_EI_CLASS])) { + if (s->sh_addr < l.a64) l.a64 = s->sh_addr; + if ((s->sh_addr + s->sh_size > h.a64) + && s->sh_size != 0) { + h.a64 = s->sh_addr + s->sh_size - 1; + } + } + s++; } - s++; } low = p->createAddress64(l.a64); high = p->createAddress64(h.a64); @@ -115,7 +141,7 @@ delete low; return NULL; } - + delete high; delete low; diff -Naur ht-2.0.18.orig/htelfshs.cc ht-2.0.18/htelfshs.cc --- ht-2.0.18.orig/htelfshs.cc 2009-04-18 00:39:58.000000000 +0200 +++ ht-2.0.18/htelfshs.cc 2010-10-03 01:01:58.000000000 +0200 @@ -98,6 +98,10 @@ ht_uformat_viewer *v = NULL; bool elf_bigendian = elf_shared->ident.e_ident[ELF_EI_DATA]==ELFDATA2MSB; if (elf_shared->ident.e_ident[ELF_EI_CLASS] == ELFCLASS32) { + // Nothing to do if no section header + if (!elf_shared->sheaders.count) + return NULL; + v = new ht_uformat_viewer(); v->init(b, DESC_ELF_SECTION_HEADERS, VC_EDIT, file, group); @@ -144,6 +148,10 @@ v->insertsub(cn); } } else if (elf_shared->ident.e_ident[ELF_EI_CLASS]==ELFCLASS64) { + // Nothing to do if no section header + if (!elf_shared->sheaders.count) + return NULL; + v = new ht_uformat_viewer(); v->init(b, DESC_ELF_SECTION_HEADERS, VC_EDIT, file, group); diff -Naur ht-2.0.18.orig/htformat.cc ht-2.0.18/htformat.cc --- ht-2.0.18.orig/htformat.cc 2009-04-07 01:35:39.000000000 +0200 +++ ht-2.0.18/htformat.cc 2010-10-03 22:27:07.000000000 +0200 @@ -322,7 +322,7 @@ init_if(*i); i++; } - ifs=i; + ifs=i; // Lol what ? } void ht_format_group::insert(ht_view *view) diff -Naur ht-2.0.18.orig/tools.cc ht-2.0.18/tools.cc --- ht-2.0.18.orig/tools.cc 2007-04-30 12:23:16.000000000 +0200 +++ ht-2.0.18/tools.cc 2010-10-03 02:39:54.000000000 +0200 @@ -49,18 +49,13 @@ { if (!max) return NULL; int *table= ht_malloc(max * sizeof(int)); - int i,j,k,l,m; + int i, j, k; for (i=0; i<max; i++) table[i] = i; for (i=0; i<max; i++) { - k=rand()%(max); - l=rand()%(max); - m=rand()%(max); - j=table[k]; - table[k]=table[l]; - table[l]=j; - j=table[i]; - table[i]=table[m]; - table[m]=j; + k = i + (rand() % (max - i)); + j = table[i]; + table[i] = table[k]; + table[k] = j; } return table; }