I am trying to link 2 files. There are 3 symbols (Assembly procedures) which I am trying to link. It worked perfectly with static linking, but when trying to do it dynamically - I receive an error.
/usr/bin/ld: warning: type and size of dynamic symbol `parse_intro' are not defined
/usr/bin/ld: warning: type and size of dynamic symbol `time_to_print' are not defined
/usr/bin/ld: warning: type and size of dynamic symbol `optimizing' are not defined
First, I am making a file into a shared library, from which I want to export 3 symbols. Code of this file:
.data
premsg:
.ascii "0x" #to make the number have distinct x16 look when printed, this will be used as a prefix before a number
msg: #placeholder msg label, reserved memory will be used to store parsed number
.space 16 #16 bytes for 32 ascii numbers
nextline:
.ascii "\n" #switching to the next line after 16 ascii numbers
var1:
.quad 0x00000000000ef12b #number which will be parsed
.global parse_intro
.global optimizing
.global time_to_print
.text
parse_intro:
#binary mask for cutting smallest 4 bits (single number) from the 8 byte number
mov $0b0000000000000000000000000000000000000000000000000000000000001111, %r9
mov $0x1, %rbx #multiplier that will be used to shift from first 4 bits to proper position in the ascii number
mov $0x0, %r12 #register that will hold first half of the reversed number
mov $0x0, %r14 #register that will hold second half of the reversed number
jmp parse_start
parse_start: #main body of the parsing number to ASCII procedure
mov %r8, %rax #making a copy of a number before shifting it
shr $4, %r8 #shifting original number to 4 numbers right to go to the next number on the next step
and %r9, %rax #taking last 4 bits from a number
cmp $0xa, %rax #checking if a number is smaller than 0xa
jl zero_to_9 #jumping to do +30 procedure if it's not x16 numeric symbol
add $0x57, %rax #adding 57 because to change a number to ASCII number from a to f you need to add x16 57
mul %rbx
mul %rbx #we multiplying it twice because we go from 8 bytes to 16 bytes
add %rax, %r12 #adding summed with 30 and increased twice by rbx coefficient piece of the initial number to the previous pieces of a number to put it together in ASCII
shl $4, %rbx #shifting rbx 4 bits to the left to increase it by mul 10 without rax shenanigans
jmp check_for_overflow #going to overflow check after adding 8 bytes to %r12
zero_to_9: #function to change from bit number to ascii number
add $0x30, %rax #adding 30 because to change a number to ASCII number from 0 to 9 you need to add x16 30
mul %rbx
mul %rbx #we multiplying it twice because we go from 8 bytes to 16 bytes
add %rax, %r12 #adding summed with 30 and increased twice by rbx coefficient piece of the initial number to the previous pieces of a number to put it together in ASCII
shl $4, %rbx #shifting rbx 4 bits to the left to increase it by mul 10 without rax shenanigans
jmp check_for_overflow #going to overflow check after adding 8 bytes to %r12
check_for_overflow: #function to store half of the value inside a second register, because it goes from 8 bytes to 16 bytes when parsed to ASCII
mov $0x1000000000000000, %rax #value for overflow check
cmp %rax, %r12 #checking if r12 is overflowed
jle looping #doing a loop to parse_start with retq if loop ends in case if %r12 is not going to get overflow
cmp $0x1, %rcx #checking if count is 1 and then
je finishing #Finishing to avoid moving %r12 to %r14 another time
mov %r12, %r14 #moving %r12 value to store in %r14
xor %r12, %r12 #resetting %r12
mov $0x1, %rbx #resetting rbx to start from the first position
jmp looping #doing a loop to parse_start with retq if loop ends
looping:
loop parse_start
retq #exiting back to start if loops end, otherwise back to parse_start and decrementing %rcx
optimizing:
#binary mask for cutting lower 4 bytes out in optimization routine
mov $0b1111111111111111111111111111111100000000000000000000000000000000, %rbx
mov $16, %rcx #the counter
movq %r8, %rax #moving the initial number value to accumulator register %rax
andq %rbx, %rax #leaving only first 32 not as 0 to check if biggest part of the number is full of 0 or not
cmp $0, %rax #checking if number is full of 0
jne finishing #first (from the left) 32 bits aren't full of 0 so we can't ignore them
subq $8, %rcx #second half of a number is full of 0, so we can only count from 8 instead of 16
retq #returning to _start
finishing:
retq #little function to jump return
time_to_print:
mov $0b1111111100000000000000000000000000000000000000000000000000000000, %r9
cmp $0, %r14 #checking if we skipped 4 bytes because the original had zeroes in the biggest part of the number
je skipped_bytes #jumping to function that will swap r14 and r12, so that lower part is kept in r14 and r12 is full of zeroes (0x30 in ASCII)
mov $56, %rcx #making a counter which would stop the jump loop which would also work as a shift left value
call byte_fun #calling the reversing procedure
mov %r14, %r12 #moving second half of the number to r12
mov %rax, %r14 #storing the first half of the number from the accumulator having the value after completing byte_fun to %r14
mov $56, %rcx #we are putting 56 and not 64 because the last step will be made after the loop to avoid additional actions
call byte_fun #reversing the second half of a number
mov %rax, %r12 #moving stored second half of the number to the different register
lea msg(%rip), %rax #storing the address of the msg inside %rax
mov %r14, (%rax) #Putting on the first half of the reserved memory by msg, linked to %rax through previous instruction, the first half of the number needed to display formatted to ASCII saying mov value (rax) makes you move the value to the address stored in the register
add $8, %rax #adding 8 to address the second half of the reserved memory in msg
mov %r12, (%rax) #putting the second half of the reversed number to an address of the last 8 bytes resrved by msg
mov $1, %rax #putting 1 to %rax for printing syscall
mov $1, %rdi #puttin 1 to %rdi for printing syscall
lea msg(%rip), %rsi #taking a position independent link to the msg label with numbers related to ascii data and putting it to a printing register %rsi
mov $16, %rdx #setting length of 16 bits (2 per 1 number) and 1 bit for newline \n char
syscall #syscalling the print with the proper number
retq #returning to the _start body
byte_fun: #start of the reverse function to save the entry point
pop %rbp #putting entry point to the %rbp register to successfully return after a few jumping back and forth
jmp byte_reverse #jumping to the main body of the reverse function
byte_reverse: #function which separates the highest 2 bits from the reversed number and then shifts the reversed number by 8 bits (2 numbers) to the left and then switches 8 bits to their proper position and pushes them to a stack.
mov %r12, %rax #putting a copy of the currently shifted reversed number to an accumulator register %rax
shl $8, %r12 #shifting reversed number to the left for the next loop cycle
and %r9, %rax #applying binary mask which will only leave 8 bytes (or 2 numbers)
shr %cl, %rax #shifting current 8 bits of a reversed number right, prior to %rcx count, to reverse their position
push %rax #pushing a shifted piece of a number to a stack
sub $8, %rcx #substracting 8 from count to represent a shifting of the next 8 bits
jne byte_reverse #if sub from %rcx not resulted in zero - we are looping
push %r12 #pushing last 2 numbers of the reversed number, shifted to the left, as the final piece of the reversed value, which will be accessed first from stack to start the reverse
mov $8, %rcx #switching count register to 8 for a future loop inside byte_back
xor %rax, %rax #cleaning up the accumulator to 0
jmp byte_back #jumping to a code which put 8 elements inside stack all together and puts them back to stack as a single entity
byte_back: #function which sums elements in the stack to get the reversed version of the number
pop %rbx #poppint highest stack element to a register
add %rbx, %rax #adding the highest element to an accumulator
loop byte_back #decrementing the %rcx counter and starting at byte back again
push %rbp #we exited the loop and now putting the address of the print procedure to the top of the stack to get back to a procedure after calling the byte_fun
retq #returning to print procedure
skipped_bytes: #function to avoid issues with printing when only 4 bytes of the original number were evaluated in parsing
#I put this print of "0x" to avoid _start code because I want to use this program as a library
mov $1, %rax #putting 1 to %rax for print syscall
mov $1, %rdi #putting 1 to %rdi for print syscall
lea premsg(%rip), %rsi #putting a link to "0x" ascii value to %rsi to print it
mov $2, %rdx #setting 2 bytes to display 2 characters
syscall #syscall for printing "0x"
mov %r12, %r14 #moving the first half of the reversed number to a register that will be pushed to a stack first, so it would be last when we get it back
mov $0x3030303030303030, %r12 #changing a second half or reversed number to ascii zeroes
jmp time_to_print #we are ready to start the printing procedure
I make this program into .so file by using a command:
gcc printing.s -shared -o libprint.so
Then, I use these 3 procedures from this .so (parse_intro, time_to_print, and optimizing)in the main file, which has this code
.data
linked_space: #space reserved for linked list nodes
.space 0x3000
list_head: #default list_head value
.quad 0x0
.quad 0x0
opening_bracket: #part of printing function construct
.ascii "["
straight_line: #part of printing function construct
.ascii "|"
closing_part: #part of printing function construct
.ascii "] -> "
last_part: #part of printing function construct, representing empty "first" node
.ascii "[empty|node]\n"
cut_error_text:
.ascii "Error: can't cut a core node\n"
.global _start
.text
add_head: #function which adds new element as head and makes a link to a previous head element
mov list_head(%rip), %rax #moving contents of a label (link to a head node) to a register
add $16, %rax #Moving the link to a point where a new node will start (1 node is 16 bytes)
mov %rbx, (%rax) #Putting a value that we want to hold in a new node inside the value address of a new head node
add $8, %rax #Moving address inside register by 8 to put a link to a previous head
mov list_head(%rip), %rdx #Moving old head address to an %rdx to put it then inside the new head
mov %rdx, (%rax) #Putting link of the old head inside a node of a new head
add $16, list_head(%rip) #Changing label which points to the head element to the new node we created
retq
cut_head: #Function which cuts the head by shifting the label 16 bytes back, with exception check to avoid touching core node
mov list_head(%rip), %rax #Putting link of the current head element which we will cutaway
add $8, %rax #Getting a link to a previous element to check if it's 0x0, which means it's a core node
cmp $0, (%rax) #Comparing it to 0
je cut_error #Jumping to error version of the cut if it's equal
sub $24, %rax #Moving to the beginning of the previous element, 16 bytes + 8 after previous add 8
mov %rax, list_head(%rip) #Moving new link to a head label
retq
cut_error: #Function which prints error text and avoid cutting the core element
mov $1, %rax #Printing error text
mov $1, %rdi
lea cut_error_text(%rip), %rsi
mov $29, %rdx
syscall
retq
pre_print: #Intro for print to put first head element, to avoid issues with loop shenanigans
push list_head(%rip)
jmp print_node #Moving to main print function
print_node: #Function which takes functions from printing code and prints linked list visually
pop %rbx #Putting stored link to node value into %rbx
push %rbx #Pushing back to a stack a link to avoid mutations of a link after working with %rbx
add $8, %rbx #Moving link to the address part of the node with the address to a previous list
mov (%rbx), %rax #Putting actual address to the previous node to check if it's 0x0, which means, it's a first empty node
cmp $0, %rax #Comparing link inside %rax to 0
je return_printing #If it's zero - moving to the final part of the print, where the first empty node is printed with \n char
mov $1, %rax #Printing opening bracket
mov $1, %rdi
lea opening_bracket(%rip), %rsi
mov $1, %rdx
syscall
pop %rbx #Getting link to the value field of the current node
mov (%rbx), %r8 #Moving it to %r8, which is a register that will contain a numeric value for future printing
push %rbx #Saving link stored inside %rbx because %rbx will be used in printing functions
call optimizing #Printing routine consists of 3 functions which need to be called from printing part of the program
call parse_intro
call time_to_print
mov $1, %rax #Printing straight line to separate value from link
mov $1, %rdi
lea straight_line(%rip), %rsi
mov $1, %rdx
syscall
pop %rbx #Putting link back from the stack again in rbx
push %rbx #Storing the link before mutating it again
add $8, %rbx #Changing link to the address which has a link to the previous element
mov (%rbx), %r8 #Moving link to %r8 to print it
call optimizing #Launching a print routine
call parse_intro
call time_to_print
mov $1, %rax #Printing closing part of the node "construct"
mov $1, %rdi
lea closing_part(%rip), %rsi
mov $5, %rdx
syscall
pop %rbx #Popping link of the printed node to shift it 16 bytes back to move to the previous node
sub $16, %rbx #Moving to the previous node
push %rbx #Putting a link to the previous node inside stack to use it later
jmp print_node #Looping back to print_node
return_printing: #Finalizing function which will print the first empty node and \n char
mov $1, %rax
mov $1, %rdi
lea last_part(%rip), %rsi
mov $13, %rdx
syscall
pop %rbx #Since we didn't pop the stored value in loop body, we need to get rid of it from stack to jump back to _start
retq
list_initialization:
lea linked_space(%rip), %rax #initializing the first node, it already has 0x0 as value and it's needed to put on the space for the linked list
mov %rax, list_head(%rip) #Putting link to the list_head, which currently contains the first node value/link 0x0, on the linked_space
retq
_start:
call list_initialization
#call pre_print #Function which prints the linked list
#mov $1, %rbx #%rbx will hold value which will be put inside new linked list node
#call add_head #Function which adds new node as head element
#call pre_print
#mov $2, %rbx
#call add_head
#call pre_print
#mov $3, %rbx
#call add_head
#call pre_print
#call cut_head #Function which cuts head element and moves link to a previous element
#call pre_print
#call cut_head
#call pre_print
#call cut_head
#call pre_print
#call cut_head
#call pre_print
mov $60, %rax #Exiting from a program
xor %rdi, %rdi
syscall
And compile it into the binary file, which should be able to run, by command:
gcc -L /home/*path_to_folder_with_so_file* -g -nostdlib -o output linkedlist.s -lprint
I also tried to compile the same file but commented out 6 lines where the program tries to access files from a dynamically shared library. Here is the "readelf" contents of this file.
https://pastebin.com/WUQz09K2
And readelf of .so file:
https://pastebin.com/1F74euqP
What am I potentially missing, why the original file can't find imported symbols from .so?
Since I can't put a comment as a solution, so, I will put an answer myself, which was given by fuz.
The important thing to do here was to pay attention to the error message (I know, how obvious). Every dynamically linked symbol in GAS assembly, even without C libraries, requires to have a type and size assigned inside the .so file, because GCC can't get this information about exported symbols on its own, and the programmer needs to explicitly give it. For example, for a function foo
foo:
...
ret
You need to give a function a type by putting
.type foo, #function
somewhere in the code, I did it on the next line after the
.global foo
line where I make the same function global, allowing it to be exported.
And, to give a size to the dynamic symbol, you need to put the
.size foo, .-foo
right after the last instruction (like, right after the "jmp" or "ret"). "Dot" is the current address and the foo is the address of the first instruction inside the "foo" function. So, by subtracting an address of "foo" out of the current address you are getting the size of a "foo".
Related
I am trying to write the char *my_strcpy(char *dest, const char *source); in assembly, at&t syntax, that should act exactly like strcpy from C. My c file looks like this:
.globl my_strcpy
my_strcpy:
push %rbp
mov %rsp, %rbp
mov %rdi, %rax
jmp copy_loop
The jump is pointless.
copy_loop:
cmp $0, (%rsi)
You didn't specify whether this should be an 8, 16, 32 or 64-bit compare. When I assemble it, I get a 32-bit compare; e.g. it sees whether the 32-bit word at address %rsi equals zero. You need to change this to cmpb $0, (%rsi).
je end
mov %rsi, %rdi
As user 500 noted, this copies the address in the %rsi register into the %rdi register, overwriting it. This is not what you want. You probably intended something like movb (%rsi), (%rdi), but no such instruction actually exists: x86 does not have such a single instruction to move memory to memory (special exception: see the movsb instruction). So you'll need to first copy the byte at address %rsi into a register, and then copy it onward with another instruction, e.g. mov (%rsi), %cl ; mov %cl, (%rdi). Note the use of the 8-bit %cl register makes it unambiguous that these should be one-byte moves.
movzbl (%rsi), %ecx is a more efficient way to load a byte on modern x86. You still store it by reading CL with mov %cl, (%rdi), but overwriting the whole RCX instead of merging into RCX is better.
addq $1, %rsi
addq $1, %rdi
You might like to learn about the inc instruction, but add is fine.
je copy_loop
I think you mean jmp copy_loop, since the jump here should happen unconditionally. (Or you should rearrange your loop so the conditional branch can be at the bottom. Since you want to copy the terminating 0 byte, you can just copy and then check for 0, like do{}while(c != 0))
end:
leave
ret
As a learning exercise, I've been handwriting assembly. I can't seem to figure out how to load the value of an address into a register.
Semantically, I want to do the following:
_start:
# read(0, buffer, 1)
mov $3, %eax # System call 3 is read
mov $0, %ebx # File handle 0 is stdin
mov $buffer, %ecx # Buffer to write to
mov $1, %edx # Length of buffer
int $0x80 # Invoke system call
lea (%ecx, %ecx), %edi # Pull the value at address into %edi
cmp $97, %edi # Compare to 'a'
je done
I've written a higher-level implementation in C:
char buffer[1];
int main()
{
read(0, buffer, 1);
char a = buffer[0];
return (a == 'a') ? 1 : 0;
}
But compiling with gcc -S produces assembly that doesn't port well into my implementation above.
I think lea is the right instruction I should be using to load the value at the given address stored in %ecx into %edi, but upon inspection in gdb, %edi contains a garbage value after this instruction is executed. Is this approach correct?
Instead of the lea instruction, what you need is:
movzbl (%ecx), %edi
That is, zero extending into the edi register the byte at the memory address contained in ecx.
_start:
# read(0, buffer, 1)
mov $3, %eax # System call 3 is read
mov $0, %ebx # File handle 0 is stdin
mov $buffer, %ecx # Buffer to write to
mov $1, %edx # Length of buffer
int $0x80 # Invoke system call
movzbl (%ecx), %edi # Pull the value at address ecx into edi
cmp $97, %edi # Compare to 'a'
je done
Some advice
You don't really need the movz instruction: you don't need a separate load operation, since you can compare the byte in memory pointed by ecx directly with cmp:
cmpb $97, (%ecx)
You may want to specify the character to be compared against (i.e., 'a') as $'a' instead of $97 in order to improve readability:
cmpb $'a', (%ecx)
Avoiding conditional branches is usually a good idea. Immediately after performing the system call, you could use the following code that uses cmov for determining the return value, which is stored in eax, instead of performing a conditional jump (i.e., the je instruction):
xor %eax, %eax # set eax to zero
cmpb $'a', (%ecx) # compare to 'a'
cmovz %edx, %eax # conditionally move edx(=1) into eax
ret # eax is either 0 or 1 at this point
edx was set to 1 prior to the system call. Therefore, this approach above relies on the fact that edx is preserved across the system call (i.e., the int 0x80 instruction).
Even better, you could use sete on al after the comparison instead of the cmov:
xor %eax, %eax # set eax to zero
cmpb $'a', (%ecx) # compare to 'a'
sete %al # conditionally set al
ret # eax is either 0 or 1 at this point
The register al, which was set to zero by means of xor %eax, %eax, will be set to 1 if the ZF flag was set by the cmp (i.e., if the byte pointed by ecx is 'a'). With this approach you don't need to care about thinking whether the syscall preserves edx or not, since the outcome doesn't depend on edx.
I've written some assembly code on making a counter to count the length of a string.
The string is -123.
I'm having just the one issue:
My negative check (cmp %r15, %r14 / je Negative_counter) is being bypassed even if I have a negative integer
.data
S: .string "123"
Result: .quad
.text
.globl main
main:
mov $S,%rdx #Storage of string
mov $S,%rbx
mov Result, %rax #Location of result storage
mov $10, %r8
mov $1, %r11 #-1 counter creation with 2s complement
not %r11 #negation of 1
add $1, %r11 #2's complement complete
mov $1, %r12 #-1 counter creation with 2s complement
not %r12 #negation of 1
add $1, %r12 #2's complement complete, -1 established
#R[rbx] is used here.
Loop1: #loop string from end to beginning
cmp $0, (%rbx) #compare base addresss value with null
je Counter_Made #if null, branch to end loop.
add $1, %r11 #increment %r11 by 1 for each digit thats not null (creates counter for 2nd loop)
add $1, %rbx #Next string digit
jmp Loop1 #reinitiate loop
#Counter of string made -149, would given counter value of 3
#R[rdx] and r14 is used here.
Counter_Made:
cmp $0,%r11 #check if %r11 is zero
je Output #End program, output null result
mov $S, %r14 #move into register 14
sub $7, %r14 #Shift to least significant bit
mov $13, %r15
and $15, %r15
cmp %r15, %r14 #Determine negativity/positivity of integer, if <0 value is negative
je Negative_counter
jmp Positive_loop
Positive_loop:
cmp %r12,%r11 #End of loop check
je Output #Store result if loop end condition satisfied
mov (%rdx), %r10 #grab first byte in address string
sub $30,(%rdx) #Conversion from 8bitASCII to 2Bit Binary
and $15, %r10 #initialize size to match
Positive_inner_loop:
mov %r11, %r9
cmp $0, %r9 #Compare loop length with 0 to see if it needs multiplication
je InnerLoopDone #Jump to inner loop done once length = 0
imul %r8, %r10 #Place holder multiplication
InnerLoopDone:
add %r10,%rax
sub $1, %r11 #Decrease Length to grab next ten multiplication place holder position
mov 1(%rdx), %rdx #next digit position
jmp Positive_loop
Negative_counter:
add $1,%rdx
jmp Negative_loop
Negative_loop:
cmp %r12,%r11
je Negative_Complement
jmp Negative_loop
Negative_Complement:
not %rdx #Convert to 2's complement with negation and then + 1
add %r14,%rdx
jmp Output
Output:
ret
I think you're talking about this block of code. I've re-commented it with less useless comments. e.g. move into register 14 doesn't tell you anything you can't tell from the mov $S, %r14 instruction itself. Comments should explain what's going on in the algorithm. Assume that the person reading the comments has a copy of the instruction reference manual available, so only comment on the mechanical details if you're doing something non-obvious. (Like using a flag that's still set from a few instructions ago).
mov $S, %r14 # r14 = pointer to the start of the string
sub $7, %r14 # r14 = pointer to 7 bytes before the beginning of the string
mov $13, %r15
and $15, %r15 # r15 = 13 & 0xF = 13
cmp %r15, %r14 #
je Negative_counter # jump if (S-7) == 13
# jmp Positive_loop # this is totally redundant, you don't need a jmp to jump over the blank line before the next block of code.
Positive_loop:
Clearly S-7 (i.e. &S[-7] in C syntax) is never going to equal 13, because addresses of things in the .data or .rodata section will never be that close to 0 on Linux.
You could have easily seen this with a debugger, by setting a breakpoint or single-stepping until you got to the cmp/je and looking at the contents of those regs.
See the bottom of the x86 tag wiki for a quick explanation of putting gdb into layout reg mode where it shows the register values as you single-step.
There are probably a lot of other things wrong with your code, too, but it's long and I didn't read it all.
This is my code so far.
.data
S: .string "-149"
Length: .byte -1
Result: .quad
.text
.globl main
main:
mov S,%rdx #Storage of string, counter, position and result in memory
mov Length, %rcx
mov Result, %rax
mov $10, %r10
mov $30, %r13
mov $-1, %r9
Loop1: #loop string from beginning to end
cmp $0,0(%rdx) #compare base addresss value with null
je Counter_Made #if null, branch to end loop.
add %r14, Length #increment length by for each digit thats not null (creates counter for 2nd loop)
add $1, %rdx #increment base by 1 to move onto next digit in string
jmp Loop1 #reinitiate loop
Counter_Made:
cmp %r15,Length #check if length is zero
je Output #End program, output null result
cmp %r15,Length(%rdx) #Determine negativity/positivity of integer
jl Negative_counter
jmp Positive_loop
Positive_loop:
cmp %r9,Length #End of loop check
je Output #Store result if loop end condition satisfied
mov %r10, Length(%rdx) #Store byte of integer in supplementary register
sub %r13, %r10 #Conversion from 8bitASCII to 2Bit Binary
imul %r11, %r10 #Place holder multiplication
add %r10, %rax #Store cumulative addition in memory
sub %r14, Length #Length decrement
jmp Positive_loop #reloop
Negative_counter:
sub %r14,Length
jmp Negative_loop
Negative_loop:
cmp %r9,Length
je Negative_Complement
mov %r10, Length(%rdx) #Store byte of integer in supplementary register
sub %r13, %r10 #Conversion from 8bitASCII to 2Bit Binary
imul %r10, %r10 #Place holder multiplication
add 0(%rdx), %rax #Store cumulative addition in memory
sub %r14, Length
jmp Negative_loop
Negative_Complement:
not %rdx #Convert to 2's complement with negation and then + 1
add %r14,%rdx
jmp Output
Output:
mov %rdx, Result
ret
#size mismatch for imul
#Specific place in memory to put output or no?
The code is supposed to convert a character string that represents any signed integer to its 2’s complement value.
I'm receiving a segmentation fault in one of my loops and I've tried multiple different methods here but to no avail - could anyone explain how I should about fixing this segfault? I'm stumped.
Here is the GDB errors
Program received signal SIGSEGV, Segmentation fault.
Loop1 () at data.s:18
18 cmp $0,0(%rdx) #compare base addresss value with null
This is the second error.
Counter_Made () at data.s:28
28 cmp $0,Length(%rdx) #Determine negativity/positivity of integer, if <0 value is negative
I'm suspecting its the Length(%rdx) method that I'm trying to interpret the loop with. Would it be better to sub $1,%rdx
You want
mov $S,%edx
to load the address of the string into %rdx. This works because the program image is always loaded into the lower 4 GB of the address space. Alternatively, you can use a %rip relative lea to load the address even if the process image is loaded outside of the first 4 GB:
lea S(%rip),%rdx
but that instruction has a somewhat longer encoding (two extra bytes).
The instruction
mov S,%rdx
loads the first eight bytes of the memory S points to into %rdx, which is not what you want.
I am making an addition program using x64 assembly, but it does not display a value when run (compiled with nasm, elf64).
section .text
global _start
_start:
mov rax, 0
add rax, [num1B]
add rax, [num2B]
mov [result], rax
mov rsi, [result]
;mov rdx, 8
mov rax, 4
mov rdi, 1
int 80h
mov rax, 1
mov rdi, 0
int 080h
section .data
num1B: dq 0Ah
num2B: dq 0Ah
result: dq 00h
Does anyone know why this is not displaying anything
1.later use printf instead of interrupts, much better,
2.why put values of numB1 and numB2 instead of their location.
Use: mov rax, numB1.
3.in 64bit nasm assembly you use the:
rdi, rsi, rbx, rcx,... Registers for putting in values for interrupts.
For example:
mov rdi, 01
mov rsi, 00
syscall
DON't USE int0x80!, for more-portability use syscall and besides int 0x80 didn't work on my system.
Hope it helps, Correct me if I'm wrong.
Looks like you want to print 'result' to stdout and you are using the 32-bit
system call values.
In 64-bit linux the system call for write is 1 and you would write to stdout like this... att&t syntax:
first strip values in %rax and push them byte by byte on stack, say %rax
holds the value 0x7ffffff8:
mov $0xa, %rbx # divisor
nibble:
xor %rdx, %rdx # will hold bytes values you need
div %rbx, %rax
push %rdx # save remainder
inc %r8 # count digit, write seems to trash %rcx
cmp $0, %rax # done?
jne nibble # no, get another digit
#set up for write to stdout
mov $1, %rax # sys_call for write
mov $1, %rdi # write to stdout
mov $result, %rsi # addr. of value to print
# now get values from stack, make ascii and write to stdout
decimal:
pop %rdx # get digit off stack
add $0x30, %dl # make ascii printable
movb %dl, result # load addr. with value
mov $1, %rdx # print 1 byte
syscall
dec %r8
jnz decimal # go till %r8 is zero
You just need to set up a 1 byte data holder for digits,either in data section:
.section .data
result:
.byte 0 # reserves 1 byte and inits to 0
or the uninitialized data area:
.section .bss
.lcomm result, 1 # reserves 1 byte
I'm sure there are better ways to do this, should give you some ideas though.
Get a 64-bit system call list, they have changed quite a lot from the 32-bit calls.