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:
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.
Amazingly, the whole mess compiles and works perfectly. All of that insane work takes a file like this:
And produces a file that looks like this:
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.
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:
And produces a file that looks like this:
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: