For my homework assignment I am supposed to convert this C code
#define UPPER 15
const int lower = 12;
int sum = 0;
int main(void) {
int i;
for (i = lower; i < UPPER; i++) {
sum += i;
}
return sum;
}
into gcc assembly. I already compiled it to first study the code before doing it per hand (obviously translating by hand is going to look much differently). This is the assembler code I received:
.file "upper.c"
.globl lower
.section .rodata
.align 4
.type lower, #object
.size lower, 4
lower:
.long 12
.globl sum
.bss
.align 4
.type sum, #object
.size sum, 4
sum:
.zero 4
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $12, -4(%rbp)
jmp .L2
.L3:
movl sum(%rip), %edx
movl -4(%rbp), %eax
addl %edx, %eax
movl %eax, sum(%rip)
addl $1, -4(%rbp)
.L2:
cmpl $14, -4(%rbp)
jle .L3
movl sum(%rip), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (SUSE Linux) 4.8.1 20130909 [gcc-4_8-branch revision 202388]"
.section .note.GNU-stack,"",#progbits
Now I was wondering if someone could give me a few examples like
where the constructors i, lower, upper and sum are located it in code
where some of the expressions i = lower or i < UPPER are located
where the for-loop starts
and such things so I can then get an idea of how the assembler code is constructed. Thank you!
If I understood correctly you question, here is the answers:
Q: where the constructors i, lower, upper and sum are located it in code?
lower is located inside .rodata section (readonly data section). It's value is initialized by linux loader during program loading stage to the value .long 12. lower constructor is a linux loader. It just loads lower value from binary image.
.globl lower
.section .rodata
.align 4
.type lower, #object
.size lower, 4
lower:
.long 12
sum is located inside .bss section (data segment containing statically-allocated variables). It's value is initialized by _init function what gets called when program execution begins. It's value is zero (.zero 4). Every variable located inside .bss section has zero as initial value (link to wiki's article for .bss).
.globl sum
.bss
.align 4
.type sum, #object
.size sum, 4
sum:
.zero 4
upper is a constant. The compiler did not put it's declaration into assembly. There is a reference to upper-1 (as $14) here:
.L2:
cmpl $14, -4(%rbp)
i is a on stack temporary variable. It's value is accessed using addresses relative %rbp (%rbp is a pointer to current function stack frame). The is no explicit declaration of i into assembly. There is no explicit stack reservation for i (no instruction like sub $0x8,%rsp at main preamble), I think, because main doesn't call another functions. Here is code for i initialization (note compiler knows that lower initial value is $12 and removes access to lower during i initialization):
movl $12, -4(%rbp)
Q: where some of the expressions i = lower or i < UPPER are located
i = lower:
movl $12, -4(%rbp)
jmp .L2
i < UPPER:
.L2:
cmpl $14, -4(%rbp)
jle .L3
i++:
addl $1, -4(%rbp)
sum += i;:
movl sum(%rip), %edx
movl -4(%rbp), %eax
addl %edx, %eax
movl %eax, sum(%rip)
return sum; (%eax register is used to hold function return value - more about this: X86 calling conventions):
jle .L3
movl sum(%rip), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
Q: where the for-loop starts
it start here:
movl $12, -4(%rbp)
jmp .L2
Related
I am trying to find the issue with below code, need to know how linker is able to track global variable multiple definition issue in below program, I am not sure much on how linker internally performs checking so requesting help to clarify.
**hello.h**
#ifndef __HELLO_
#define __HELLO_
static int s = 20;
int g = 10;
#endif
**cat hello1.c**
#include <stdio.h>
#include "hello.h"
//int g = 10;
int main()
{
g++;
s++;
printf("g : %d s : %d\n", g, s);
function();
return 0;
}
**cat hello2.c**
#include <stdio.h>
#include "hello.h"
//extern int g;
void function()
{
g++;
s++;
printf("g : %d s : %d\n", g, s);
}
**gcc -save-temps hello1.c hello2.c -o hello**
hello2.o:(.data+0x4): multiple definition of `g'
hello1.o:(.data+0x4): first defined here
**collect2: error: ld returned 1 exit status**
I don't need solution to fix this error, I know above program will throw multiple definition error of g as above but can anyone please explain how it tracks this error at linking stage?.
Here is the output of assembly code.
**cat hello1.s**
.file "hello1.c"
.data
.align 4
.type s, #object
.size s, 4
s:
.long 20
.globl g
.align 4
.type g, #object
.size g, 4
g:
.long 10
.section .rodata
.LC0:
.string "g : %d s : %d\n"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl g(%rip), %eax
addl $1, %eax
movl %eax, g(%rip)
movl s(%rip), %eax
addl $1, %eax
movl %eax, s(%rip)
movl s(%rip), %edx
movl g(%rip), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
call function
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
.section .note.GNU-stack,"",#progbits
**cat hello2.s**
.file "hello2.c"
.data
.align 4
.type s, #object
.size s, 4
s:
.long 20
.globl g
.align 4
.type g, #object
.size g, 4
g:
.long 10
.section .rodata
.LC0:
.string "g : %d s : %d\n"
.text
.globl function
.type function, #function
function:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl g(%rip), %eax
addl $1, %eax
movl %eax, g(%rip)
movl s(%rip), %eax
addl $1, %eax
movl %eax, s(%rip)
movl s(%rip), %edx
movl g(%rip), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size function, .-function
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
.section .note.GNU-stack,"",#progbits
Please share me the reference if this query is already posted earlier, unable to track the similar link.
Internally compiler generates two distinct object files hello1.o and hello2.o. Each of them exports variable g:
$ readelf -sW hello1.o | grep GLOBAL
8: 0000000000000000 4 OBJECT GLOBAL DEFAULT 2 g
$ readelf -sW hello2.o | grep GLOBAL
10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 2 g
Linker detects that there is more then one definition of g when building a global symbol table for the executable and reports an error.
Let say I have the (x << n) | (x >> (-n & 63)) expression.
There is nothing conditional in it.
So, to my understanding, it will be executed in constant time.
Indeed, when I compile the following code using gcc -O3 -S:
#include <stdint.h>
// rotate left x by n places assuming n < 64
uint64_t rotl64(uint64_t x, uint8_t n) {
return (x << n) | (x >> (-n & 63));
}
I get, on linux/amd64, the following output (which executes in constant time):
.file "test.c"
.text
.p2align 4
.globl rotl64
.type rotl64, #function
rotl64:
.LFB0:
.cfi_startproc
movq %rdi, %rax
movl %esi, %ecx
rolq %cl, %rax
ret
.cfi_endproc
.LFE0:
.size rotl64, .-rotl64
.ident "GCC: (Alpine 9.3.0) 9.3.0"
.section .note.GNU-stack,"",#progbits
However, on linux/386 I get an output that contains conditional jumps:
.file "test.c"
.text
.p2align 4
.globl rotl64
.type rotl64, #function
rotl64:
.LFB0:
.cfi_startproc
pushl %edi
.cfi_def_cfa_offset 8
.cfi_offset 7, -8
pushl %esi
.cfi_def_cfa_offset 12
.cfi_offset 6, -12
movl 12(%esp), %eax
movl 16(%esp), %edx
movzbl 20(%esp), %ecx
movl %eax, %esi
movl %edx, %edi
shldl %esi, %edi
sall %cl, %esi
testb $32, %cl
je .L4
movl %esi, %edi
xorl %esi, %esi
.L4:
negl %ecx
andl $63, %ecx
shrdl %edx, %eax
shrl %cl, %edx
testb $32, %cl
je .L5
movl %edx, %eax
xorl %edx, %edx
.L5:
orl %esi, %eax
orl %edi, %edx
popl %esi
.cfi_restore 6
.cfi_def_cfa_offset 8
popl %edi
.cfi_restore 7
.cfi_def_cfa_offset 4
ret
.cfi_endproc
.LFE0:
.size rotl64, .-rotl64
.ident "GCC: (Alpine 9.3.0) 9.3.0"
.section .note.GNU-stack,"",#progbits
From what I understand, here the 64 bits operations have to be emulated, hence the need of conditional jumps.
Does GCC provide a builtin function that indicates if an expression will be compiled with no jumps?
If it isn't the case, how can I know if an expression will be executed in constant time?
Is this a problem for timing sensitive applications like security?
Does GCC provide a builtin function that indicates if an expression will be compiled with no jumps?
No.
If it isn't the case, how can I know if an expression will be executed in constant time?
By looking at the generated assembly code.
Is this a problem for timing sensitive applications like security?
Yes. That's why in these cases don't trust the compilers (and porters/package builders changing compiler settings) and rather implement it in assembly.
There are some constant time functions in general libc's, like in OpenBSD and FreeBSD. Like timingsafe_bcmp and timingsafe_memcmp, which are written in pure C, but their authors trust their packagers not to be like Debian or Ubuntu, who are assumed to break it.
Many other such functions are in the various security libraries itself, but even then you can safely assume that they are broken. For sure in OpenSSL and libsodium in many cases.
No such a function does not exist.
And unless you are writing the compiler (you're not) you should not really care about the actual machine code being generated. The compiler is free to optimize that code anyway it sees fit (as long as it is correct) depending on the options you pass in. And with -O3 you should get the fastest code, even with jumps.
If there were a function like you suggested, you're code would be tied to a single version of a single compiler with a particular set of optimization options. In other words: bye bye portability.
I have written simple code in order to study assembler.
Task im trying to do is in assembler part: mycode.s
Im curious, how would i be able to manually change position of my local variable int var ( it is located on stack, because its local) to lowest possible location(address) in stack...
Im using following code:
#include<stdio.h>
int c = 0;
int main()
{
int var = 0;
if( var == c)
{
printf("here");
}
return 0;
}
when i assemble my code with gcc -m32 -S mycode.c
i get:
.file "mycode.c"
.globl c
.bss
.align 4
.type c, #object
.size c, 4
c:
.zero 4
.section .rodata
.LC0:
.string "here"
.text
.globl main
.type main, #function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
movl $0, -12(%ebp)
movl c, %eax
cmpl %eax, -12(%ebp)
jne .L2
subl $12, %esp
pushl $.LC0
call printf
addl $16, %esp
.L2:
movl $0, %eax
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0"
.section .note.GNU-stack,"",#progbits
What instructions can i use to check the current stack addresses and find the lowest possible address (for example: 0x003 < 0x004).. Thanks
Hi I'm new to the gcc's built-in atomic functions. And I'm using the test-and-set one. You may find the reference here
Here's the question:
I've done this code:
#define bool int
#define true 1
#define false 0
int main() {
bool lock = true;
bool val = __sync_lock_test_and_set(&lock, true);
return 0;
}
What I intend to do is to check the assembly instruction of __sync_lock_test_and_set. I've used:
gcc -S [filename].c
And the result is:
.file "test_and_set.c"
.file "test_and_set.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $16, %esp
movl $1, -8(%ebp)
movl $1, %eax
xchgl -8(%ebp), %eax
movl %eax, -4(%ebp)
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.1"
However, I can't find where the test_and_set instruction is...
As you can see, I'm using gcc-4.8.1, and the environment is MAC OSX 10.10(I'm sure that this gcc is not what Apple provides. I've compiled this by myself)
Thanks!
movl $1, -8(%ebp) # lock = true
movl $1, %eax # true argument
xchgl -8(%ebp), %eax # the test-and-set
It is an atomic exchange, which returns the previous value (that's the test part) and writes 1 into the variable (the set part). This is used to implement mutexes. After the operation the lock will be held by somebody - either the original owner or your code that has just acquired it. That's why it's safe to write a value of 1. The original value is returned, so you can distinguish between those two events. If the original value was 0 then you got the lock and can proceed, otherwise you need to wait because somebody else has it.
I am trying to understand how to embed assembly language in C (using gcc on x86_64 architecture). I wrote this program to increment the value of a single variable. But I am getting garbage value as output. And ideas why?
#include <stdio.h>
int main(void) {
int x;
x = 4;
asm("incl %0": "=r"(x): "r0"(x));
printf("%d", x);
return 0;
}
Thanks
Update The program is giving expected result on gcc 4.8.3 but not on gcc 4.6.3. I am pasting the assembly output of the non-working code:
.file "abc.c"
.section .rodata
.LC0:
.string "%d"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
pushq %rbx
subq $24, %rsp
movl $4, -20(%rbp)
movl -20(%rbp), %eax
incl %edx
movl %edx, %ebx
.cfi_offset 3, -24
movl %ebx, -20(%rbp)
movl $.LC0, %eax
movl -20(%rbp), %edx
movl %edx, %esi
movq %rax, %rdi
movl $0, %eax
call printf
movl $0, %eax
addq $24, %rsp
popq %rbx
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",#progbits
You don't need to say x twice; once is sufficient:
asm("incl %0": "+r"(x));
The +r says that the value will be input and output.
Your way, with separate inputs and output registers, requires that you take the input from %1, add one, and write the output to %0, but you can't do that with incl.
The reason it works on some compilers is because GCC is free to allocate both %0 and %1 to the same register, and appears to have done so in those cases, but it does not have to. Incidentally, if you want to prevent GCC allocating an input and output to the same register (say, if you want to initialize the output before using the input to calculate a final output), you need to use the & modifier.
The documentation for the modifiers is here.