This question already has answers here:
What are the calling conventions for UNIX & Linux system calls (and user-space functions) on i386 and x86-64
(4 answers)
Segfault when loading from [esp] in 64-bit code
(1 answer)
Closed 1 year ago.
I wrote the following x86-64 functions to be called in a C program:
The first one takes in a 2-digit hexadecimal character and rotates its bit towards the right by one bit, i.e, if '12'(means 0x12 but 0x is not feeded as input) is rotated right by one bit to give '09'(0x09)
.file "rotate_right.s"
.section .rodata
.data
.globl rotate_right
.type rotate_right, #function
.text
rotate_right:
pushq %rbp
movq %rsp,%rbp
pushq %rsi
pushq %rdi
pushq %rbx
subl $4, %esp
movb 8(%ebp), %al
sarb $1, %al
leave
ret
.size rotate_right, .-rotate_right
Similarly, this function rotates the bits to the left one position, so '12'(0x12) becomes '24'(0x24).
.file "rotate_left.s"
.section .rodata
.data
.globl rotate_left
.type rotate_left, #function
.text
rotate_left:
pushq %rbp
movq %rsp,%rbp
pushq %rsi
pushq %rdi
pushq %rbx
subl $4, %esp
movb 8(%ebp), %al
sarb $1, %al
leave
ret
.size rotate_left, .-rotate_left
The create_key() function gets a four bit input like 0110 and outputs an 8-bit output as unsigned int i.e 01100110:
.file "create_key.s"
.section .rodata
ask_key:
.string "Enter 4-bit key:"
.data
.globl create_key
.type create_key, #function
.text
create_key:
pushq %rbp
# stack holding
movq %rsp, %rbp
movl $ask_key, %edi
# printing the ask string
movl $0, %eax
# calling the C functions
call printf
movl $0,%esi
# rsi is set to 0. the key
pushq %rsi
# take it to the stack
# call getchar for getting each key bit
call getchar
popq %rsi
subl $48,%eax
# doing this will give us 1 or 0 if the we input 1 or 0
sall $1,%esi
# shift the key by one bit
orl %eax,%esi
# OR key and the sigle input
pushq %rsi
# push rsi to stack to save the value in rsi
# Do the above operation a total of 4 times
call getchar
popq %rsi
subl $48,%eax
sall $1,%esi
orl %eax,%esi
pushq %rsi
call getchar
popq %rsi
subl $48,%eax
sall $1,%esi
orl %eax,%esi
pushq %rsi
call getchar
popq %rsi
subl $48,%eax
sall $1,%esi
orl %eax,%esi
# copy first 4-bits of the key into %rax
movl %esi,%eax
#left shift the key 4 times
sall $4,%esi
# OR the secont 4-bits into %rax
orl %esi,%eax
leave
ret
# return the values and end the function
.size create_key, .-create_key
Here is the C-program,
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
extern unsigned int create_key();
extern unsigned char rotate_left(unsigned char x);
extern unsigned char rotate_right(unsigned char x);
int main(){
/* This Part Takes The Input To Be Ciphered
And Prints The Hexadecimal Value*/
char word[200], outword[400], xor_hex[400], hex_rot[400], ch, hex[2];
unsigned int i_key, encodant, rotated;
int i, len, j;
/* i_key is the integer equvivalent of the cipher key*/
printf("enter cleartext:");
i = 0;
ch = getchar();
while(ch!='\n'){
word[i] = ch;
++i;
ch = getchar();
}
fflush(stdin);
len = i;
word[i] = '\0';
printf("%s\n", word);
printf("hex encoding:\n");
for(i = 0; i<len; i++){
sprintf(outword+(i*2), "%02X", word[i]);
}
for(i=0;i<(2*len);i++){
if(i%2==0 & i>0)printf(" ");
if(i%20==0 & i>0)printf("\n");
printf("%c", outword[i]);
}
printf("\n");
/* This Part Asks For The Cipher Key */
i_key = create_key();
/* XOR Encoding of the Hex Cyphertext*/
for(i=0;i<len*2;i+=2){
hex[0] = outword[i];
hex[1] = outword[i+1];
encodant = (int)strtol(hex, NULL, 16);
sprintf(xor_hex+(i), "%02X", (i_key^encodant));
}
/* Encoding the text using bit rotation */
j=1;
for(i=0;i<len*2;i+=2){
hex[0]=xor_hex[i];
hex[1]=xor_hex[i+1];
encodant = (int)strtol(hex, NULL, 16);
if(j%2==0)rotated = rotate_right(encodant);
else rotated = rotate_left(encodant);
j++;
sprintf(hex_rot+(i), "%02X", rotated);
}
/* Printing The Finished Ciphered Text */
printf("hex ciphertext:\n");
for(i=0;i<(2*len);i++){
if(i%2==0 & i>0)printf(" ");
if(i%20==0 & i>0)printf("\n");
printf("%c", hex_rot[i]);
}
printf("\n");
return 0;
}
The function prototypes can't be changed, i.e rotate functions must be char and have char parameters, the create_key function is good appearently, but my code gives segmentation fault. I don't know what to do in this situation so any help is appreciated.
There is no need to do anything with the stack here. Take the argument from rdi (SysV) or rcx (Win32), put it in al, rotate and return:
.file "rotate.S"
.text
.globl rotate_right
rotate_right:
mov %rdi, %rax
shrb $1, %al
ret
.globl rotate_left
rotate_left:
mov %rdi, %rax
shlb $1, %al
ret
.end
Now that is GNU as syntax, it may require some adjustment for AT&T asm.
To test it:
#include <stdio.h>
unsigned char rotate_left(unsigned char);
unsigned char rotate_right(unsigned char);
int main() {
printf("%02x %02x\n", rotate_left(0x12), rotate_right(0x12));
return 0;
}
Prints:
24 09
Related
I'm trying to make a write function in x64 that I can call in a C file.
I have the following files
write.s
.text
.globl write
write:
// stack thing
pushq %rbp
movq %rsp, %rbp
// function arguments as done by the C convention
movl %edi, -4(%rbp) // fd
movl %esi, -8(%rbp) // buf
movl %edx, -12(%rbp) // length
// write
movq $1, %rax // syscall 1 for write
movq -4(%rbp), %rdi // fd to rdi
movq -8(%rbp), %rsi // buf to rsi
movq -12(%rbp), %rdx // len to rdx
syscall
// return
movq %rbp, %rsp
popq %rbp
ret
write.h
void write(int fd, char *buf, int len);
main.c
#include "write.h"
int main() {
int fd = 1;
char *buf = "hi";
int len = 2;
write(fd, buf, len);
return 0;
}
The problem is that when I compile this with gcc -no-pie -o main write.s main.c
and run ./main it doesn't output anything.
I'm sorry if this is some obvious mistake, as I am not that familiar with x64 assembly.
Taking the following C code
#include <stdio.h>
void test(unsigned char buffer[], int size) {
for (int i = 0; i < size; i++) {
unsigned char data = buffer[i];
printf("%c", data);
}
}
void main() {
unsigned char buffer[5] = "Hello";
test(buffer, 5);
return;
}
and compiling it the flags -fno-stack-protector -fno-asynchronous-unwind-tables -fno-unroll-loops for clarity produces the following assembly for the test() function:
test:
testl %esi, %esi
jle .L6
pushq %rbp
leal -1(%rsi), %eax
pushq %rbx
leaq 1(%rdi,%rax), %rbp
movq %rdi, %rbx
subq $8, %rsp
.p2align 4,,10
.p2align 3
.L3:
movzbl (%rbx), %edi
addq $1, %rbx
call putchar#PLT
cmpq %rbp, %rbx
jne .L3
addq $8, %rsp
popq %rbx
popq %rbp
ret
.p2align 4,,10
.p2align 3
.L6:
ret
.size test, .-test
.section .text.startup,"ax",#progbits
.p2align 4
It seems to me like the L3 label here is completely useless since it is never jumped to or entered. (Except by jne .L3, but that instruction is inside of the L3 label already).
Can anyone explain how and why this assembly still produces the expected effect?
If you read the assembler code from the top you will see that it reaches .L3, plus it also jumps to it with jne .L3, which is your for loop in C.
Take the following C program that has two functions:
// main.c
int times_two(int num) {
int b = num + num;
return b;
}
int main(void) {
int a=2;
int num = times_two(a) + a;
return num;
}
Is the following a more-or-less accurate way to represent that in x86 assembly? I know this is verbose and I have a bunch of extra push/pop and such on the stacks that I don't need, but does the following more or less faithfully follow the C code?
SYS_EXIT = 60
.globl _start
_start:
call main
mov %eax, %edi
mov $SYS_EXIT, %eax
syscall
main:
# function() {...
push %rbp
mov %rsp, %rbp
# int a = 2
sub $8, %rsp
movl $2, -4(%rbp)
# times_two(a)
movq -4(%rbp), %rdi
call times_two
# ... + a
addl -4(%rbp), %eax
# ...} // (return value already in eax)
add $8, %rsp
pop %rbp
ret
times_two:
push %rbp
mov %rsp, %rbp
# return num + num
xor %eax, %eax # <-- update: not necessary: next line wipes it out anyways.
mov %edi, %eax # <-- update: could also do lea (%eax,,2) to multiply by constant
add %edi, %eax
pop %rbp
ret
If not, what may I be screwing up or missing/doing wrong?
I have a code in c language that needs to be translated to assembly x86.
Here is the c code:
int rb (FILE *f){
int s;
char c;
s = fr(&c, 1, 1, f);
if (s <= 0) return -1;
return (int)c;
}
So far I got to this assembly code that gives me Segmentation fault:
rb:
pushl %ebp
movl %esp,%ebp
pushl 8(%ebp)
pushl $1
pushl $1
leal 12(%ebp), %eax
pushl %eax
call fr
jz ng
jns ex
ng:
pushl $1
negl %eax
ex:
popl %ebp
ret
Can anyone help me to solve this? :)
Both Gcc and Clang can generate the assember for you. It might not always be easy to read but this is how to do it:
Make the snippet you want to inspect compilable with no errors. Note, I've changed your example to take a pointer to an integer as an argument because in your example you were declaring a char on the stack and then returning it ie Undefined Bahaviour.
Create a file called foo.c with this in it:
#include <stdio.h>
extern size_t fr(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
int rb (FILE *f, int *c){
int s;
s = fr(c, 1, 1, f);
if (s <= 0) return -1;
return *c;
}
Compile it using the S flag to gcc ie
gcc-5 -S -O0 -Wall -pedantic -std=c11 foo.c
The open the following file foo.s
.text
.globl _rb
_rb:
LFB1:
pushq %rbp
LCFI0:
movq %rsp, %rbp
LCFI1:
subq $32, %rsp
movq %rdi, -24(%rbp)
movq %rsi, -32(%rbp)
movq -24(%rbp), %rdx
movq -32(%rbp), %rax
movq %rdx, %rcx
movl $1, %edx
movl $1, %esi
movq %rax, %rdi
call _fr
movl %eax, -4(%rbp)
cmpl $0, -4(%rbp)
jg L2
movl $-1, %eax
jmp L3
L2:
movq -32(%rbp), %rax
movl (%rax), %eax
L3:
leave
LCFI2:
ret
LFE1:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
....
.... snipped
....
Now you have the assembler on x86 for the code you wanted. Note, you can play around with various options to change the output in particular the optimization levels will drastically change the output.
I have main function in C that runs code in assembly. I just want to make simple sum:
main.c
#include <stdio.h>
extern int addByAssembly(int first_number, int second_number);
int main (int argc, char **argv)
{
int sum=0;
sum = addByAssembly(5,4);
printf ("%d\n",sum);
return 0;
}
addByAssembly.s
.data
SYSREAD = 0
SYSWRITE = 1
SYSEXIT = 60
STDOUT = 1
STDIN = 0
EXIT_SUCCESS = 0
.text
#.global main
#main:
#call write
#movq $SYSEXIT, %rax
#movq $EXIT_SUCCESS, %rdi
#syscall
#********
.globl addByAssembly
addByAssembly:
pushq %rbp
movq %rsp, %rbp
movq 16(%rsp), %rax
addq 24(%rsp), %rax
movq %rbp, %rsp
popq %rbp
But i got mess in my sum. It looks like i badly pass arguments, beause if I do this:
movq $123, %rax
return value is 123. I 've tried many ways, but cannot find how to make this properly to sum.
Thanks 'Jester' for so much effort and time to get me this explained!
To sum up. Passing parameters from C to As ( and as well from As to C) has its own ABI convention.
As you can see there, params are send on order:
1) rdi
2) rsi
3) rdx
... and so on...
In case you have more parameters than in convention, it will be pushed to stack.
So in my case:
.globl addByAssembly
addByAssembly:
pushq %rbp
movq %rsp, %rbp
--movq 16(%rsp), %rax #this was wrong as my params are
--addq 24(%rsp), %rax # first in %rdi, second in %rsi
++lea (%rdi, %rsi), %rax # in my case this line will do
# %rdi+%rsi -> %rax (learn lea, usefull command)
# REMEMBER return value is always in %rax!
movq %rbp, %rsp
popq %rbp