How I knew I was in trouble with a school project

FUCK THE POLICE

911 EVERY DAY
My professor gave us a project which involved manipulating arrays of structs in assembly. I looked up information on how to do this online, and the first relevant link that appeared was written by him.

Here is the relevant code, for any interested in torturing themselves by attempting to read it or simply gazing in fascination at the mind of insanity:

Code:
#include <stdio.h>#include <stdlib.h>
#include <string.h>
#include <stddef.h>


typedef struct {
  int salary;
  int sales;
  char name[64];
  int bonus;
  int total;
} salesman;


salesman read(FILE* sFile);
int average(salesman *compSales, int i);
void bonus(salesman *compSales, int i, int average);
int comparator ( const void * elem1, const void * elem2 ); 
void report(salesman compSales[], int i);


int main()
{
  FILE* sFile;
  sFile = fopen ("sales.txt","r");
  salesman compSales[100];
  int i = 0;
  
  while(!feof(sFile))
  {
    compSales[i]=read(sFile);
    i++;
  }
  if(compSales[i-1].salary == -1)            //if eof wasn't correctly detected and it went through the function oncemore, this decrements the counter to the correct size
  {
    i--;
  }
  fclose(sFile);
  
  int ave = average(&compSales[0], i);
  bonus(&compSales[0], i, ave);
  int count;
  for(count = 0; count<=i;count++)
  {
    compSales[count].total=compSales[count].salary+compSales[count].bonus;
    int new = 0;
  }
  qsort(compSales,i,80,comparator);
  report(compSales, i);
  
  int newb = 45;
  
  return 0;
}


salesman read(FILE* sFile)
{
  salesman tempSales;
  char line[128];
  fgets(line, 128, sFile);
  char* first = strtok(line, " ");        //use strtok to split up line
  char* last = strtok(NULL, " ");
  char* name = malloc(64);
  sprintf(name, "%s %s", first, last);        //conctanate first and last name
  strcpy(tempSales.name, name);            //copy name into struct
  
  char* salary = strtok(NULL, " ");
  if(salary !=NULL)                //eof sometimes isn't correctly detected on the first try, necessitating all of this to avoid a segmentation fault.
  {
    tempSales.salary = atoi(salary);
    char* sales = strtok(NULL, "\n");
    tempSales.sales = atoi(sales);
  }
  else
  {
    tempSales.salary = -1;            //signal that eof wasn't detected correctly
  }
  
  return tempSales;
}


void report(salesman compSales[], int i)
{
  FILE* bFile;
  bFile = fopen("bonuses.txt", "w+");
  fprintf(bFile,"Name                   Salary     Sales      Bonus    Total Salary\n");
  fprintf(bFile,"--------------------  --------   --------   -------   ------------\n");
  int count;
  i--;
  for(count = 0; i>=count; i--)
  {
    fprintf(bFile,"%-21s %-10d %-10d %-10d %d \n",compSales[i].name, compSales[i].salary, compSales[i].sales, compSales[i].bonus, compSales[i].total);
  }
    
}

And here is the assembly portion which was linked. I know that the preferred method for manipulating structs in assembly is to define them in assembly itself, but I wasn't sure how that would transfer over to C and I wasn't interested in finding out. So I merely memorized the offsets of the struct and data items and defined the struct in C, then passed the pointer to the first item in the struct into the assembly function. I also found out while writing this that I seemed to have corrupted my stack pointer in the C portion of the code at some point, and that cmp was not setting flags, so I had to use sub instead.

Code:
global    average
global  bonus
global  comparator


    segment .data
ave     dd    0


    segment .text
average:
    
push        rbp
mov        rbp, rsp
.s_sales    equ    4
.s_size        equ    80        ;offset for salesman
;int acc;    using eax as acc    Not using stack for local variables because it gives me a segmentation fault
;int count;    using r14 as count
;for(i = 0, count<i, cont++)        ;i is variable passed into function
xor        ecx,ecx            ;zeroing count
xor        eax,eax            ;zeroing acc
mov        r14, rcx        ;zeroing r14, which stores count
.for:        
mov        r13, rcx        ;preserving count
sub         rcx, rsi        ;cmp was not setting flags, so I used sub
jge        .end_for
mov        rcx, r13        ;set count back to preserved value
;{
 ; acc += salesman[i].sales;
add        eax, [rdi+.s_sales]
add        rdi, .s_size        ;increment salesman
mov        rcx, r14        ;i
inc        rcx
mov        r14, rcx
jmp        .for
;}
.end_for:
;int ave = acc/n;            ;ave is rax
mov        rdx, 0            ;rax=rax/rsi
idiv        rsi            
;return ave;    
            
leave
ret


bonus:
push        rbp
mov        rbp, rsp
.s_sales    equ    4
.s_bonus    equ    72
.s_size        equ    80
;int count                ; //ecx = count
;int temp
xor        eax, eax        ; //eax = temp
mov        [ave], edx        ; //moving ave (edx) to ebx so that edx can be used in idiv and as temp2
;int temp2
xor        edx, edx
;for(i = 0, count<i, count++)
xor        ecx,ecx            ; //zeroing count
xor        eax,eax            ; //zeroing acc
mov        r14, rcx        ; //zeroing r14, which stores count
.for:        
mov        r13, rcx        ; //preserving count
sub         rcx, rsi        ; //cmp was not setting flags, so I used sub
jge        .end_for
mov        rcx, r13        ; {   // set count back to preserved value
xor        eax, eax        
mov        edx, [ave]        ; temp2 = ave;
mov         eax, [rdi+.s_sales]    ; temp = compSales[i].sales;
sub        eax, edx        ; temp = temp - temp2;
jg        .if            ; if(temp>ave)
jle        .else
.if:    
xor        edx, edx        ;  {
mov         ecx, 20
idiv        ecx            ;     temp=temp/20;
mov         [rdi+.s_bonus], eax    ;     compSales[i].bonus = temp;
jmp        .endif            ;  }
.else:                    ;  else
xor        edx, edx                    ;  {
mov         [rdi+.s_bonus],edx     ;    compSales[i].bonus = 0;
.endif:
add        rdi, .s_size        ;    //incrementing compSales
mov        rcx, r14        
inc        rcx
mov        r14, rcx        ;  }
jmp        .for            ;}
.end_for:


leave
ret


comparator:
.s_final    equ    76
xor        eax, eax
mov        eax, [rdi+.s_final]
sub        eax, [rsi+.s_final]
ret

Amazingly, the whole mess compiles and works perfectly. All of that insane work takes a file like this:

ls9R6.png


And produces a file that looks like this:

bRGaR.png


It will take up to one hundred names! Actually, make that 99.

And it only took an entire night and morning, 12 hours of vyvanse insanity! Clearly, a great use of my time. And this is a skill for which I will never receive a dime in my life, because employers want you to crank out generic, safe code, not indulge your ego by hacking assembly and producing something unreadable which is 10% faster, riddled with bugs, and difficult to expand upon.
 
Last edited:
Most of our code is php.

We use a ton of arrays to pull up all the different objects necessary to bring you this awesome page...

It looks a bit like it, not exactly like it.

At least you don't have to deal with pointers. Pointers are one thing that sounds incredibly simple when you first read about them but can be so hard to have a full understanding of. And C has an incredibly ghetto implementation of arrays that basically just amounts to a pointer to the first element which you add stuff to to get other elements. This is actually just syntatic sugar on the way you do it in assembly. And instead of having a string class, the strings really just consist of putting characters into these really ghetto arrays.
 
Last edited:
Back
Top